From 1653f967bbdf292f7211c11a2a0fd4b286eebb1a Mon Sep 17 00:00:00 2001 From: Alain Pitiot Date: Mon, 1 Aug 2022 10:12:25 +0200 Subject: [PATCH] upgraded dialog box; various small fixes; revised documentation --- README.md | 4 +- docs/AudioClip.html | 2132 +++ docs/AudioClipPlayer.html | 1672 +++ docs/BuilderKeyResponse.html | 306 + docs/ButtonStim.html | 4100 +++++ docs/Clock.html | 752 + docs/Color.html | 6506 ++++++++ docs/CountdownTimer.html | 824 ++ docs/EventEmitter.html | 895 ++ docs/EventManager.html | 2386 +++ docs/ExperimentHandler.html | 2010 +++ docs/FaceDetector.html | 1744 +++ docs/FaceDetector_FaceDetector.html | 166 - docs/Form.html | 4669 ++++++ docs/GUI.html | 2417 +++ docs/GratingStim.html | 3195 ++++ docs/ImageStim.html | 1899 +++ docs/KeyPress.html | 301 + docs/Keyboard.html | 1793 +++ docs/Logger.html | 2177 +++ docs/Microphone.html | 1946 +++ docs/MinimalStim.html | 1213 ++ docs/MonotonicClock.html | 987 ++ docs/Mouse.html | 1757 +++ docs/MovieStim.html | 2363 +++ docs/MultiStairHandler.html | 1410 ++ docs/Polygon.html | 2125 +++ docs/QuestHandler.html | 2262 +++ docs/Rect.html | 2214 +++ docs/Scheduler.html | 1478 ++ docs/ServerManager.html | 4671 ++++++ docs/ShapeStim.html | 1780 +++ docs/{module-data.Shelf.html => Shelf.html} | 3480 ++--- docs/Slider.html | 7169 +++++++++ docs/SoundPlayer.html | 1079 ++ docs/SpeechRecognition.html | 1436 ++ docs/TextBox.html | 4353 ++++++ docs/TextStim.html | 2296 +++ docs/TonePlayer.html | 1657 +++ docs/TrackPlayer.html | 1682 +++ docs/Transcript.html | 323 + docs/Window.html | 2327 +++ docs/core_EventManager.js.html | 130 +- docs/core_GUI.js.html | 725 +- docs/core_Keyboard.js.html | 125 +- docs/core_Logger.js.html | 93 +- docs/core_MinimalStim.js.html | 105 +- docs/core_Mouse.js.html | 103 +- docs/core_PsychoJS.js.html | 123 +- docs/core_ServerManager.js.html | 568 +- docs/core_Window.js.html | 153 +- docs/core_WindowMixin.js.html | 64 +- docs/data_ExperimentHandler.js.html | 109 +- docs/data_MultiStairHandler.js.html | 120 +- docs/data_QuestHandler.js.html | 140 +- docs/data_Shelf.js.html | 200 +- docs/data_TrialHandler.js.html | 108 +- docs/fonts/Montserrat/Montserrat-Bold.eot | Bin 0 -> 106135 bytes docs/fonts/Montserrat/Montserrat-Bold.ttf | Bin 0 -> 47088 bytes docs/fonts/Montserrat/Montserrat-Bold.woff | Bin 0 -> 112872 bytes docs/fonts/Montserrat/Montserrat-Bold.woff2 | Bin 0 -> 85436 bytes docs/fonts/Montserrat/Montserrat-Regular.eot | Bin 0 -> 106287 bytes docs/fonts/Montserrat/Montserrat-Regular.ttf | Bin 0 -> 46392 bytes docs/fonts/Montserrat/Montserrat-Regular.woff | Bin 0 -> 112020 bytes .../fonts/Montserrat/Montserrat-Regular.woff2 | Bin 0 -> 85240 bytes docs/fonts/OpenSans-Bold-webfont.eot | Bin 19544 -> 0 bytes docs/fonts/OpenSans-Bold-webfont.svg | 1830 --- docs/fonts/OpenSans-Bold-webfont.woff | Bin 22432 -> 0 bytes docs/fonts/OpenSans-BoldItalic-webfont.eot | Bin 20133 -> 0 bytes docs/fonts/OpenSans-BoldItalic-webfont.svg | 1830 --- docs/fonts/OpenSans-BoldItalic-webfont.woff | Bin 23048 -> 0 bytes docs/fonts/OpenSans-Italic-webfont.eot | Bin 20265 -> 0 bytes docs/fonts/OpenSans-Italic-webfont.svg | 1830 --- docs/fonts/OpenSans-Italic-webfont.woff | Bin 23188 -> 0 bytes docs/fonts/OpenSans-Light-webfont.eot | Bin 19514 -> 0 bytes docs/fonts/OpenSans-Light-webfont.svg | 1831 --- docs/fonts/OpenSans-Light-webfont.woff | Bin 22248 -> 0 bytes docs/fonts/OpenSans-LightItalic-webfont.eot | Bin 20535 -> 0 bytes docs/fonts/OpenSans-LightItalic-webfont.svg | 1835 --- docs/fonts/OpenSans-LightItalic-webfont.woff | Bin 23400 -> 0 bytes docs/fonts/OpenSans-Regular-webfont.eot | Bin 19836 -> 0 bytes docs/fonts/OpenSans-Regular-webfont.svg | 1831 --- docs/fonts/OpenSans-Regular-webfont.woff | Bin 22660 -> 0 bytes .../sourcesanspro-light-webfont.eot | Bin 0 -> 19390 bytes .../sourcesanspro-light-webfont.svg | 978 ++ .../sourcesanspro-light-webfont.ttf | Bin 0 -> 67760 bytes .../sourcesanspro-light-webfont.woff | Bin 0 -> 21132 bytes .../sourcesanspro-light-webfont.woff2 | Bin 0 -> 16080 bytes .../sourcesanspro-regular-webfont.eot | Bin 0 -> 20014 bytes .../sourcesanspro-regular-webfont.svg | 1049 ++ .../sourcesanspro-regular-webfont.ttf | Bin 0 -> 68656 bytes .../sourcesanspro-regular-webfont.woff | Bin 0 -> 21720 bytes .../sourcesanspro-regular-webfont.woff2 | Bin 0 -> 16636 bytes docs/hardware_Camera.js.html | 724 + docs/index.html | 70 +- docs/module-core.BuilderKeyResponse.html | 269 - docs/module-core.EventManager.html | 1736 --- docs/module-core.GUI.html | 1114 -- docs/module-core.KeyPress.html | 265 - docs/module-core.Keyboard.html | 1386 -- docs/module-core.Logger.html | 810 - docs/module-core.MinimalStim.html | 1098 -- docs/module-core.Mouse.html | 1748 --- docs/module-core.PsychoJS.html | 1663 ++- docs/module-core.ServerManager.html | 412 - docs/module-core.Window.html | 2132 --- docs/module-core.WindowMixin.html | 575 +- docs/module-core.html | 95 +- docs/module-data.ExperimentHandler.html | 1675 --- docs/module-data.MultiStairHandler.html | 1225 -- docs/module-data.QuestHandler.html | 1551 -- docs/module-data.TrialHandler.html | 2278 +-- docs/module-data.html | 2273 +-- docs/module-hardware.Camera.html | 2531 ++++ docs/module-sound.AudioClip.html | 1216 -- docs/module-sound.AudioClipPlayer.html | 1617 -- docs/module-sound.Microphone.html | 1441 -- docs/module-sound.Sound.html | 1297 +- docs/module-sound.SoundPlayer.html | 1048 -- docs/module-sound.TonePlayer.html | 1528 -- docs/module-sound.TrackPlayer.html | 1627 -- docs/module-sound.Transcriber.html | 1395 -- docs/module-sound.Transcript.html | 171 - docs/module-sound.html | 99 +- docs/module-util.Clock.html | 495 - docs/module-util.Color.html | 2076 --- docs/module-util.ColorMixin.html | 451 +- docs/module-util.CountdownTimer.html | 667 - docs/module-util.EventEmitter.html | 1009 -- docs/module-util.MixinBuilder.html | 230 - docs/module-util.MonotonicClock.html | 873 -- docs/module-util.PsychObject.html | 1346 +- docs/module-util.Scheduler.html | 960 -- docs/module-util.html | 12301 +++++++++++++--- docs/module-visual.ButtonStim.html | 1042 -- docs/module-visual.Camera.html | 2416 --- docs/module-visual.FaceDetector.html | 1708 --- docs/module-visual.Form.html | 2359 --- docs/module-visual.GratingStim.html | 4450 ------ docs/module-visual.ImageStim.html | 1306 -- docs/module-visual.MovieStim.html | 1095 -- docs/module-visual.Polygon.html | 1036 -- docs/module-visual.Rect.html | 1042 -- docs/module-visual.ShapeStim.html | 1258 -- docs/module-visual.Slider.html | 2888 ---- docs/module-visual.TextBox.html | 2364 --- docs/module-visual.TextStim.html | 1640 -- docs/module-visual.VisualStim.html | 2520 +++- docs/module-visual.html | 122 +- docs/module.data.MultiStairHandler.html | 600 - docs/module.data.QuestHandler.html | 845 -- docs/scripts/collapse.js | 20 + docs/scripts/linenumber.js | 18 +- docs/scripts/nav.js | 12 + docs/scripts/polyfill.js | 4 + docs/scripts/search.js | 83 + docs/sound_AudioClip.js.html | 105 +- docs/sound_AudioClipPlayer.js.html | 107 +- docs/sound_Microphone.js.html | 106 +- docs/sound_Sound.js.html | 98 +- docs/sound_SoundPlayer.js.html | 92 +- docs/sound_SpeechRecognition.js.html | 460 + docs/sound_TonePlayer.js.html | 108 +- docs/sound_TrackPlayer.js.html | 107 +- docs/styles/jsdoc-default.css | 358 - docs/styles/jsdoc.css | 765 + docs/styles/prettify-jsdoc.css | 111 - docs/styles/prettify-tomorrow.css | 132 - docs/styles/prettify.css | 79 + docs/util_Clock.js.html | 121 +- docs/util_Color.js.html | 155 +- docs/util_ColorMixin.js.html | 67 +- docs/util_EventEmitter.js.html | 82 +- docs/util_Pixi.js.html | 65 +- docs/util_PsychObject.js.html | 74 +- docs/util_Scheduler.js.html | 116 +- docs/util_Util.js.html | 197 +- docs/visual_ButtonStim.js.html | 107 +- docs/visual_Camera.js.html | 657 - docs/visual_FaceDetector.js.html | 123 +- docs/visual_Form.js.html | 191 +- docs/visual_GratingStim.js.html | 154 +- docs/visual_ImageStim.js.html | 160 +- docs/visual_MovieStim.js.html | 129 +- docs/visual_Polygon.js.html | 113 +- docs/visual_Rect.js.html | 112 +- docs/visual_ShapeStim.js.html | 123 +- docs/visual_Slider.js.html | 514 +- docs/visual_TextBox.js.html | 219 +- docs/visual_TextStim.js.html | 150 +- docs/visual_VisualStim.js.html | 125 +- package-lock.json | 11 + package.json | 5 +- src/core/EventManager.js | 70 +- src/core/GUI.js | 665 +- src/core/Keyboard.js | 65 +- src/core/Logger.js | 33 +- src/core/MinimalStim.js | 45 +- src/core/Mouse.js | 43 +- src/core/PsychoJS.js | 63 +- src/core/ServerManager.js | 128 +- src/core/Window.js | 88 +- src/core/WindowMixin.js | 4 +- src/data/ExperimentHandler.js | 49 +- src/data/MultiStairHandler.js | 58 +- src/data/QuestHandler.js | 78 +- src/data/Shelf.js | 107 +- src/data/TrialHandler.js | 48 +- src/data/index.js | 1 - src/hardware/Camera.js | 3 +- src/index.css | 13 + src/sound/AudioClip.js | 45 +- src/sound/AudioClipPlayer.js | 47 +- src/sound/Microphone.js | 46 +- src/sound/Sound.js | 38 +- src/sound/SoundPlayer.js | 32 +- .../sound/SpeechRecognition.js | 171 +- src/sound/TonePlayer.js | 48 +- src/sound/TrackPlayer.js | 47 +- src/sound/index.js | 3 +- src/util/Clock.js | 61 +- src/util/Color.js | 95 +- src/util/ColorMixin.js | 7 +- src/util/EventEmitter.js | 22 +- src/util/Pixi.js | 5 +- src/util/PsychObject.js | 14 +- src/util/Scheduler.js | 56 +- src/util/Util.js | 122 +- src/visual/ButtonStim.js | 47 +- src/visual/FaceDetector.js | 63 +- src/visual/Form.js | 121 +- src/visual/GratingStim.js | 92 +- src/visual/ImageStim.js | 98 +- src/visual/MovieStim.js | 64 +- src/visual/Polygon.js | 53 +- src/visual/Rect.js | 52 +- src/visual/ShapeStim.js | 59 +- src/visual/Slider.js | 188 +- src/visual/TextBox.js | 121 +- src/visual/TextStim.js | 90 +- src/visual/VisualStim.js | 52 +- 241 files changed, 116688 insertions(+), 85371 deletions(-) create mode 100644 docs/AudioClip.html create mode 100644 docs/AudioClipPlayer.html create mode 100644 docs/BuilderKeyResponse.html create mode 100644 docs/ButtonStim.html create mode 100644 docs/Clock.html create mode 100644 docs/Color.html create mode 100644 docs/CountdownTimer.html create mode 100644 docs/EventEmitter.html create mode 100644 docs/EventManager.html create mode 100644 docs/ExperimentHandler.html create mode 100644 docs/FaceDetector.html delete mode 100644 docs/FaceDetector_FaceDetector.html create mode 100644 docs/Form.html create mode 100644 docs/GUI.html create mode 100644 docs/GratingStim.html create mode 100644 docs/ImageStim.html create mode 100644 docs/KeyPress.html create mode 100644 docs/Keyboard.html create mode 100644 docs/Logger.html create mode 100644 docs/Microphone.html create mode 100644 docs/MinimalStim.html create mode 100644 docs/MonotonicClock.html create mode 100644 docs/Mouse.html create mode 100644 docs/MovieStim.html create mode 100644 docs/MultiStairHandler.html create mode 100644 docs/Polygon.html create mode 100644 docs/QuestHandler.html create mode 100644 docs/Rect.html create mode 100644 docs/Scheduler.html create mode 100644 docs/ServerManager.html create mode 100644 docs/ShapeStim.html rename docs/{module-data.Shelf.html => Shelf.html} (52%) create mode 100644 docs/Slider.html create mode 100644 docs/SoundPlayer.html create mode 100644 docs/SpeechRecognition.html create mode 100644 docs/TextBox.html create mode 100644 docs/TextStim.html create mode 100644 docs/TonePlayer.html create mode 100644 docs/TrackPlayer.html create mode 100644 docs/Transcript.html create mode 100644 docs/Window.html create mode 100644 docs/fonts/Montserrat/Montserrat-Bold.eot create mode 100644 docs/fonts/Montserrat/Montserrat-Bold.ttf create mode 100644 docs/fonts/Montserrat/Montserrat-Bold.woff create mode 100644 docs/fonts/Montserrat/Montserrat-Bold.woff2 create mode 100644 docs/fonts/Montserrat/Montserrat-Regular.eot create mode 100644 docs/fonts/Montserrat/Montserrat-Regular.ttf create mode 100644 docs/fonts/Montserrat/Montserrat-Regular.woff create mode 100644 docs/fonts/Montserrat/Montserrat-Regular.woff2 delete mode 100644 docs/fonts/OpenSans-Bold-webfont.eot delete mode 100644 docs/fonts/OpenSans-Bold-webfont.svg delete mode 100644 docs/fonts/OpenSans-Bold-webfont.woff delete mode 100644 docs/fonts/OpenSans-BoldItalic-webfont.eot delete mode 100644 docs/fonts/OpenSans-BoldItalic-webfont.svg delete mode 100644 docs/fonts/OpenSans-BoldItalic-webfont.woff delete mode 100644 docs/fonts/OpenSans-Italic-webfont.eot delete mode 100644 docs/fonts/OpenSans-Italic-webfont.svg delete mode 100644 docs/fonts/OpenSans-Italic-webfont.woff delete mode 100644 docs/fonts/OpenSans-Light-webfont.eot delete mode 100644 docs/fonts/OpenSans-Light-webfont.svg delete mode 100644 docs/fonts/OpenSans-Light-webfont.woff delete mode 100644 docs/fonts/OpenSans-LightItalic-webfont.eot delete mode 100644 docs/fonts/OpenSans-LightItalic-webfont.svg delete mode 100644 docs/fonts/OpenSans-LightItalic-webfont.woff delete mode 100644 docs/fonts/OpenSans-Regular-webfont.eot delete mode 100644 docs/fonts/OpenSans-Regular-webfont.svg delete mode 100644 docs/fonts/OpenSans-Regular-webfont.woff create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff create mode 100644 docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 create mode 100644 docs/hardware_Camera.js.html delete mode 100644 docs/module-core.BuilderKeyResponse.html delete mode 100644 docs/module-core.EventManager.html delete mode 100644 docs/module-core.GUI.html delete mode 100644 docs/module-core.KeyPress.html delete mode 100644 docs/module-core.Keyboard.html delete mode 100644 docs/module-core.Logger.html delete mode 100644 docs/module-core.MinimalStim.html delete mode 100644 docs/module-core.Mouse.html delete mode 100644 docs/module-core.ServerManager.html delete mode 100644 docs/module-core.Window.html delete mode 100644 docs/module-data.ExperimentHandler.html delete mode 100644 docs/module-data.MultiStairHandler.html delete mode 100644 docs/module-data.QuestHandler.html create mode 100644 docs/module-hardware.Camera.html delete mode 100644 docs/module-sound.AudioClip.html delete mode 100644 docs/module-sound.AudioClipPlayer.html delete mode 100644 docs/module-sound.Microphone.html delete mode 100644 docs/module-sound.SoundPlayer.html delete mode 100644 docs/module-sound.TonePlayer.html delete mode 100644 docs/module-sound.TrackPlayer.html delete mode 100644 docs/module-sound.Transcriber.html delete mode 100644 docs/module-sound.Transcript.html delete mode 100644 docs/module-util.Clock.html delete mode 100644 docs/module-util.Color.html delete mode 100644 docs/module-util.CountdownTimer.html delete mode 100644 docs/module-util.EventEmitter.html delete mode 100644 docs/module-util.MixinBuilder.html delete mode 100644 docs/module-util.MonotonicClock.html delete mode 100644 docs/module-util.Scheduler.html delete mode 100644 docs/module-visual.ButtonStim.html delete mode 100644 docs/module-visual.Camera.html delete mode 100644 docs/module-visual.FaceDetector.html delete mode 100644 docs/module-visual.Form.html delete mode 100644 docs/module-visual.GratingStim.html delete mode 100644 docs/module-visual.ImageStim.html delete mode 100644 docs/module-visual.MovieStim.html delete mode 100644 docs/module-visual.Polygon.html delete mode 100644 docs/module-visual.Rect.html delete mode 100644 docs/module-visual.ShapeStim.html delete mode 100644 docs/module-visual.Slider.html delete mode 100644 docs/module-visual.TextBox.html delete mode 100644 docs/module-visual.TextStim.html delete mode 100644 docs/module.data.MultiStairHandler.html delete mode 100644 docs/module.data.QuestHandler.html create mode 100644 docs/scripts/collapse.js create mode 100644 docs/scripts/nav.js create mode 100644 docs/scripts/polyfill.js create mode 100644 docs/scripts/search.js create mode 100644 docs/sound_SpeechRecognition.js.html delete mode 100644 docs/styles/jsdoc-default.css create mode 100644 docs/styles/jsdoc.css delete mode 100644 docs/styles/prettify-jsdoc.css delete mode 100644 docs/styles/prettify-tomorrow.css create mode 100644 docs/styles/prettify.css delete mode 100644 docs/visual_Camera.js.html rename docs/sound_Transcriber.js.html => src/sound/SpeechRecognition.js (53%) diff --git a/README.md b/README.md index 43333eb..acddc00 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ PsychoJS is a JavaScript library that makes it possible to run neuroscience, psychology, and psychophysics experiments in a browser. It is the online counterpart of the [PsychoPy](http://www.psychopy.org/) Python library. -You can create online experiments from the [PsychoPy Builder](http://www.psychopy.org/builder/builder.html), you can find and adapt existing experiments on [pavlovia.org](https://www.pavlovia.org), or create them from scratch: the PsychoJS API is available [here](https://psychopy.github.io/psychojs/). +You can create online experiments from the [PsychoPy Builder](http://www.psychopy.org/builder/builder.html), you can find and adapt existing experiments on [pavlovia.org](https://www.pavlovia.org), or create them from scratch. PsychoJS is an open-source project. You can contribute by submitting pull requests to the [PsychoJS GitHub repository](https://github.com/psychopy/psychojs), and discuss issues and current and future features on the [Online category of the PsychoPy Forum](https://discourse.psychopy.org/c/online). @@ -55,8 +55,8 @@ Alain Pitiot - [@apitiot](https://github.com/apitiot) The PsychoJS library was initially written by [Ilixa](http://www.ilixa.com) with support from the [Wellcome Trust](https://wellcome.ac.uk). It is now a collaborative effort, supported by the [Chan Zuckerberg Initiative](https://chanzuckerberg.com/) (2020-2021) and [Open Science Tools](https://opensciencetools.org/) (2020-): - Alain Pitiot - [@apitiot](https://github.com/apitiot) -- Sotiri Bakagiannis - [@thewhodidthis](https://github.com/thewhodidthis) - Nikita Agafonov - [@lightest](https://github.com/lightest) +- Sotiri Bakagiannis - [@thewhodidthis](https://github.com/thewhodidthis) - Jonathan Peirce - [@peircej](https://github.com/peircej) - Thomas Pronk - [@tpronk](https://github.com/tpronk) - Hiroyuki Sogo - [@hsogo](https://github.com/hsogo) diff --git a/docs/AudioClip.html b/docs/AudioClip.html new file mode 100644 index 0000000..0ed740c --- /dev/null +++ b/docs/AudioClip.html @@ -0,0 +1,2132 @@ + + + + + + AudioClip - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

AudioClip

+ + + + + + + +
+ +
+ +

+ sound + + AudioClip +

+ +

AudioClip encapsulates an audio recording.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new AudioClip(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

name + + +String + + + + + + <optional>
+ + + + + +
+ + 'audioclip' + +

the name used when logging messages

format + + +string + + + + + + + + + + + +

the format for the audio file

sampleRateHz + + +number + + + + + + + + + + + +

the sampling rate

data + + +Blob + + + + + + + + + + + +

the audio data, in the given format, at the given sampling rate

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Engine :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
GOOGLE + + +Symbol + + + +

Google Cloud Speech-to-Text.

+ + + + + + +
+

Recognition engines.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) Status :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
CREATED + + +Symbol + + + +
DECODING + + +Symbol + + + +
READY + + +Symbol + + + +
+ + + + + + +
+

AudioClip status.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(protected) _base64ArrayBuffer(arrayBuffer) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert an array buffer to a base64 string.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
arrayBuffer + +

the input buffer

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the base64 encoded input buffer

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(protected) _decodeAudio()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Decode the formatted audio data (e.g. webm) into a 32bit float PCM audio buffer.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _GoogleTranscribe(transcriptionKey, languageCode) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Transcribe the audio clip using the Google Cloud Speech-To-Text Engine.

+

ref: https://cloud.google.com/speech-to-text/docs/reference/rest/v1/speech/recognize

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
transcriptionKey + + +String + + + +

the secret key to the Google service

languageCode + + +String + + + +

the BCP-47 language code for the recognition, e.g. 'en-GB'

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

a promise resolving to the transcript and associated +transcription confidence

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

download()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Offer the audio clip to the participant as a sound file to download.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getDuration() → {Promise.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the audio clip, in seconds.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the duration of the audio clip

+
+ + + +
+
+ Type +
+
+ +Promise.<number> + + +
+
+ + + + + + + + + + +

setVolume(volume)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the volume of the playback.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
volume + + +number + + + +

the volume of the playback (must be between 0.0 and 1.0)

+ + + + + + + + + + + + + + + + + + + + + + + + +

(async) startPlayback()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the audio clip.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopPlayback(fadeDurationopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the audio clip.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fadeDuration + + +number + + + + + + <optional>
+ + + + + +
+ + 17 + +

how long the fading out should last, in ms

+ + + + + + + + + + + + + + + + + + + + + + + + +

(async) transcribe(options) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Transcribe the audio clip.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
engine + + +Symbol + + + +

the speech-to-text engine

languageCode + + +String + + + +

the BCP-47 language code for the recognition, +e.g. 'en-GB'

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

a promise resolving to the transcript and associated +transcription confidence

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

upload()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Upload the audio clip to the pavlovia server.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/AudioClipPlayer.html b/docs/AudioClipPlayer.html new file mode 100644 index 0000000..6c8d83c --- /dev/null +++ b/docs/AudioClipPlayer.html @@ -0,0 +1,1672 @@ + + + + + + AudioClipPlayer - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

AudioClipPlayer

+ + + + + + + +
+ +
+ +

+ sound + + AudioClipPlayer +

+ +

This class handles the playback of an audio clip, e.g. a microphone recording.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new AudioClipPlayer(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

audioClip + + +Object + + + + + + + + + + + +

the module:sound.AudioClip

startTime + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

start of playback (in seconds)

stopTime + + +number + + + + + + <optional>
+ + + + + +
+ + -1 + +

end of playback (in seconds)

stereo + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to play the sound or track in stereo

volume + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

volume of the sound (must be between 0 and 1.0)

loops + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

how many times to repeat the track or tone after it has played *

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(static) accept(sound) → {Object|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether this player can play the given sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sound + + +module:sound.Sound + + + +

the sound object, which should be an AudioClip

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

an instance of AudioClipPlayer if sound is an AudioClip or undefined otherwise

+
+ + + +
+
+ Type +
+
+ +Object +| + +undefined + + +
+
+ + + + + + + + + + +

getDuration() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the AudioClip, in seconds.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the duration of the clip, in seconds

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

play(loops, fadeDurationopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
loops + + +number + + + + + + + + + + + +

how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.

fadeDuration + + +number + + + + + + <optional>
+ + + + + +
+ + 17 + +

how long should the fading in last in ms

+ + + + + + + + + + + + + + + + + + + + + + + + +

setDuration(duration_s)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the duration of the audio clip.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
duration_s + + +number + + + +

the duration of the clip in seconds

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLoops(loops)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the number of loops.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loops + + +number + + + +

how many times to repeat the clip after it has played once. If loops == -1, the clip will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

setVolume(volume, muteopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the volume of the playback.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
volume + + +number + + + + + + + + + + + +

the volume of the playback (must be between 0.0 and 1.0)

mute + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to mute the playback

+ + + + + + + + + + + + + + + + + + + + + + + + +

stop(fadeDurationopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the sound immediately.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fadeDuration + + +number + + + + + + <optional>
+ + + + + +
+ + 17 + +

how long the fading out should last, in ms

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/BuilderKeyResponse.html b/docs/BuilderKeyResponse.html new file mode 100644 index 0000000..84b980d --- /dev/null +++ b/docs/BuilderKeyResponse.html @@ -0,0 +1,306 @@ + + + + + + BuilderKeyResponse - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

BuilderKeyResponse

+ + + + + + + +
+ +
+ +

+ BuilderKeyResponse +

+ +

Utility class used by the experiment scripts to keep track of a clock and of the current status (whether or not we are currently checking the keyboard)

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new BuilderKeyResponse(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +

Classes

+ +
+
BuilderKeyResponse
+
+
+ + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ButtonStim.html b/docs/ButtonStim.html new file mode 100644 index 0000000..c803113 --- /dev/null +++ b/docs/ButtonStim.html @@ -0,0 +1,4100 @@ + + + + + + ButtonStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

ButtonStim

+ + + + + + + +
+ +
+ +

+ visual + + ButtonStim +

+ +

ButtonStim visual stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new ButtonStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
win + + +module:core.Window + + + + + + + + + + + +

the associated Window

name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

text + + +string + + + + + + <optional>
+ + + + + +
+ + "" + +

the text to be rendered

font + + +string + + + + + + <optional>
+ + + + + +
+ + "Arial" + +

the font family

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the text

anchor + + +string + + + + + + <optional>
+ + + + + +
+ + "center" + +

horizontal alignment

units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the text size and position

color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color("white") + +

the background color

fillColor + + +Color + + + + + + <optional>
+ + + + + +
+ + Color("darkgrey") + +

the fill color

borderColor + + +Color + + + + + + <optional>
+ + + + + +
+ + Color("white") + +

the border color

borderWidth + + +Color + + + + + + <optional>
+ + + + + +
+ + 0 + +

the border width

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

letterHeight + + +number + + + + + + <optional>
+ + + + + +
+ +

the height of the text

bold + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the text is bold

italic + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the text is italic

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

isClicked

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Is this button currently being clicked on?

+
+ + + + + + + + + + +

numClicks

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

How many times has this button been clicked on?

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _addEventListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add event listeners to text-box object. Method is called internally upon object construction.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getAnchor() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert the anchor attribute into numerical values.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the anchor, as an array of numbers in [0,1]
  • +
+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _getDefaultLetterHeight() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the default letter height given the stimulus' units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the letter height corresponding to this stimulus' units.
  • +
+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected) _getTextInputOptions()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the TextInput options applied to the PIXI.TextInput.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • take size into account
  • +
+
+ +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

clear()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clears the current text value.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getText() → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

For accessing the underlying input value.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the current text value of the underlying input element.
  • +
+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

reset()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clears the current text value or sets it back to match the placeholder.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setAlignment(alignment, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the alignment attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
alignment + + +boolean + + + + + + + + + + + + left + +

alignment of the text

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setAnchor(anchor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the anchor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
anchor + + +boolean + + + + + + + + + + + + center + +

anchor of the textbox

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setBorderColor(borderColor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the borderColor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
borderColor + + +Color + + + + + + + + + + + +

border color of the text box

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setColor(color, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the color attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
color + + +boolean + + + + + + + + + + + +

color of the text

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFillColor(fillColor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the fillColor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fillColor + + +boolean + + + + + + + + + + + +

fill color of the text box

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFitToContent(fitToContent, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the fitToContent attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fitToContent + + +boolean + + + + + + + + + + + +

whether or not to autoresize textbox to fit to text content

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFont(font, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the font for textbox.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
font + + +string + + + + + + + + + + + + Arial + +

the font family

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLanguageStyle(languageStyle, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the languageStyle attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
languageStyle + + +String + + + + + + + + + + + + LTR + +

text direction in textbox, accepts values ["LTR", "RTL", "Arabic"]

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLetterHeight(fontSizeopt, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set letterHeight (font size) for textbox.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fontSize + + +string + + + + + + <optional>
+ + + + + +
+ + <default value> + +

the size of the font

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setSize(size, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the size attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
size + + +boolean + + + + + + + + + + + +

whether or not to wrap the text at the given width

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setText(text)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

For tweaking the underlying input value.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +string + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Clock.html b/docs/Clock.html new file mode 100644 index 0000000..2685592 --- /dev/null +++ b/docs/Clock.html @@ -0,0 +1,752 @@ + + + + + + Clock - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Clock

+ + + + + + + +
+ +
+ +

+ util + + Clock +

+ +

Clock is a MonotonicClock that also offers the possibility of being reset.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Clock()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

add(deltaTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add more time to the clock's 'start' time (t0).

+

Note: by adding time to t0, the current time is pushed forward (it becomes +smaller). As a consequence, getTime() may return a negative number.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
deltaTime + + +number + + + + + + <optional>
+ + + + + +

the time to be added to the clock's start time (t0)

+ + + + + + + + + + + + + + + + + + + + + + + + +

getLastResetTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current offset being applied to the high resolution timebase used by this Clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the offset (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

getTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current time on this clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the current time (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

reset(newTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the time on the clock.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
newTime + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the new time on the clock.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Color.html b/docs/Color.html new file mode 100644 index 0000000..d111e6e --- /dev/null +++ b/docs/Color.html @@ -0,0 +1,6506 @@ + + + + + + Color - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Color

+ + + + + + + +
+ +
+ +

+ util + + Color +

+ +

This class handles multiple color spaces, and offers various +static methods for converting colors from one space to another.

+

The constructor accepts the following color representations: +

    +
  • a named color, e.g. 'aliceblue' (the colorspace must be RGB)
  • +
  • an hexadecimal string representation, e.g. '#FF0000' (the colorspace must be RGB)
  • +
  • an hexadecimal number representation, e.g. 0xFF0000 (the colorspace must be RGB)
  • +
  • a triplet of numbers, e.g. [-1, 0, 1], [0, 128, 255] (the numbers must be within the range determined by the colorspace)
  • +
+

+

Note: internally, colors are represented as a [r,g,b] triplet with r,g,b in [0,1].

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Color(objopt, colorspaceopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • implement HSV, DKL, and LMS colorspaces
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
obj + + +string +| + +number +| + +Array.<number> +| + +undefined + + + + + + <optional>
+ + + + + +
+ + 'black' + +

an object representing a color

colorspace + + +module:util.Color#COLOR_SPACE +| + +undefined + + + + + + <optional>
+ + + + + +
+ + Color.COLOR_SPACE.RGB + +

the colorspace of that color

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) COLOR_SPACE :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
RGB + + +Symbol + + + +

RGB colorspace: [r,g,b] with r,g,b in [-1, 1]

RGB255 + + +Symbol + + + +

RGB255 colorspace: [r,g,b] with r,g,b in [0, 255]

+ + + + + + +
+

Color spaces.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) NAMED_COLORS :string

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
aliceblue + + +string + + + +
antiquewhite + + +string + + + +
aqua + + +string + + + +
aquamarine + + +string + + + +
azure + + +string + + + +
beige + + +string + + + +
bisque + + +string + + + +
black + + +string + + + +
blanchedalmond + + +string + + + +
blue + + +string + + + +
blueviolet + + +string + + + +
brown + + +string + + + +
burlywood + + +string + + + +
cadetblue + + +string + + + +
chartreuse + + +string + + + +
chocolate + + +string + + + +
coral + + +string + + + +
cornflowerblue + + +string + + + +
cornsilk + + +string + + + +
crimson + + +string + + + +
cyan + + +string + + + +
darkblue + + +string + + + +
darkcyan + + +string + + + +
darkgoldenrod + + +string + + + +
darkgray + + +string + + + +
darkgrey + + +string + + + +
darkgreen + + +string + + + +
darkkhaki + + +string + + + +
darkmagenta + + +string + + + +
darkolivegreen + + +string + + + +
darkorange + + +string + + + +
darkorchid + + +string + + + +
darkred + + +string + + + +
darksalmon + + +string + + + +
darkseagreen + + +string + + + +
darkslateblue + + +string + + + +
darkslategray + + +string + + + +
darkslategrey + + +string + + + +
darkturquoise + + +string + + + +
darkviolet + + +string + + + +
deeppink + + +string + + + +
deepskyblue + + +string + + + +
dimgray + + +string + + + +
dimgrey + + +string + + + +
dodgerblue + + +string + + + +
firebrick + + +string + + + +
floralwhite + + +string + + + +
forestgreen + + +string + + + +
fuchsia + + +string + + + +
gainsboro + + +string + + + +
ghostwhite + + +string + + + +
gold + + +string + + + +
goldenrod + + +string + + + +
gray + + +string + + + +
grey + + +string + + + +
green + + +string + + + +
greenyellow + + +string + + + +
honeydew + + +string + + + +
hotpink + + +string + + + +
indianred + + +string + + + +
indigo + + +string + + + +
ivory + + +string + + + +
khaki + + +string + + + +
lavender + + +string + + + +
lavenderblush + + +string + + + +
lawngreen + + +string + + + +
lemonchiffon + + +string + + + +
lightblue + + +string + + + +
lightcoral + + +string + + + +
lightcyan + + +string + + + +
lightgoldenrodyellow + + +string + + + +
lightgray + + +string + + + +
lightgrey + + +string + + + +
lightgreen + + +string + + + +
lightpink + + +string + + + +
lightsalmon + + +string + + + +
lightseagreen + + +string + + + +
lightskyblue + + +string + + + +
lightslategray + + +string + + + +
lightslategrey + + +string + + + +
lightsteelblue + + +string + + + +
lightyellow + + +string + + + +
lime + + +string + + + +
limegreen + + +string + + + +
linen + + +string + + + +
magenta + + +string + + + +
maroon + + +string + + + +
mediumaquamarine + + +string + + + +
mediumblue + + +string + + + +
mediumorchid + + +string + + + +
mediumpurple + + +string + + + +
mediumseagreen + + +string + + + +
mediumslateblue + + +string + + + +
mediumspringgreen + + +string + + + +
mediumturquoise + + +string + + + +
mediumvioletred + + +string + + + +
midnightblue + + +string + + + +
mintcream + + +string + + + +
mistyrose + + +string + + + +
moccasin + + +string + + + +
navajowhite + + +string + + + +
navy + + +string + + + +
oldlace + + +string + + + +
olive + + +string + + + +
olivedrab + + +string + + + +
orange + + +string + + + +
orangered + + +string + + + +
orchid + + +string + + + +
palegoldenrod + + +string + + + +
palegreen + + +string + + + +
paleturquoise + + +string + + + +
palevioletred + + +string + + + +
papayawhip + + +string + + + +
peachpuff + + +string + + + +
peru + + +string + + + +
pink + + +string + + + +
plum + + +string + + + +
powderblue + + +string + + + +
purple + + +string + + + +
red + + +string + + + +
rosybrown + + +string + + + +
royalblue + + +string + + + +
saddlebrown + + +string + + + +
salmon + + +string + + + +
sandybrown + + +string + + + +
seagreen + + +string + + + +
seashell + + +string + + + +
sienna + + +string + + + +
silver + + +string + + + +
skyblue + + +string + + + +
slateblue + + +string + + + +
slategray + + +string + + + +
slategrey + + +string + + + +
snow + + +string + + + +
springgreen + + +string + + + +
steelblue + + +string + + + +
tan + + +string + + + +
teal + + +string + + + +
thistle + + +string + + + +
tomato + + +string + + + +
turquoise + + +string + + + +
violet + + +string + + + +
wheat + + +string + + + +
white + + +string + + + +
whitesmoke + + +string + + + +
yellow + + +string + + + +
yellowgreen + + +string + + + +
+ + + + + + +
+

Named colors.

+
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + + + + +

hex

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the hexadecimal color code equivalent of this Color.

+
+ + + + + + + + + + +

int

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer code equivalent of this Color.

+
+ + + + + + + + + + +

rgb

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0,1] RGB triplet equivalent of this Color.

+
+ + + + + + + + + + +

rgb255

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0,255] RGB triplet equivalent of this Color.

+
+ + + + + + + + + + +

rgbFull

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [-1,1] RGB triplet equivalent of this Color.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected, static) _checkTypeAndRange(arg, rangeopt) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check that the argument is an array of numbers of size 3, and, potentially, that its elements fall within the range.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
arg + + +any + + + + + + + + + +

the argument

range + + +Array.<number> + + + + + + <optional>
+ + + + + +

the lower and higher bounds of the range

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether the argument is an array of numbers of size 3, and, potentially, whether its elements fall within the range (if range is not undefined)

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

(protected, static) _intToRgb(hex) → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0, 1] based RGB triplet equivalent of the integer color code.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hex + + +number + + + +

the integer color code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the [0, 1] RGB equivalent

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected, static) _intToRgb255(hex) → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0, 255] based RGB triplet equivalent of the integer color code.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hex + + +number + + + +

the integer color code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the [0, 255] RGB equivalent

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected, static) _rgb255ToHex(rgb255) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the hexadecimal color code equivalent of the [0, 255] RGB triplet.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb255 + + +Array.<number> + + + +

the [0, 255] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the hexadecimal color code equivalent

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(protected, static) _rgb255ToInt(rgb255) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer equivalent of the [0, 255] RGB triplet.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb255 + + +Array.<number> + + + +

the [0, 255] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the integer equivalent

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected, static) _rgbToHex(rgb) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the hexadecimal color code equivalent of the [0, 1] RGB triplet.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb + + +Array.<number> + + + +

the [0, 1] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the hexadecimal color code equivalent

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(protected, static) _rgbToInt(rgb) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer equivalent of the [0, 1] RGB triplet.

+

Note: this is the fast, unsafe version which does not check for argument sanity

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb + + +Array.<number> + + + +

the [0, 1] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the integer equivalent

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(static) hexToRgb(hex) → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0,1] RGB triplet equivalent of the hexadecimal color code.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hex + + +string + + + +

the hexadecimal color code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the [0,1] RGB triplet equivalent

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(static) hexToRgb255(hex) → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the [0,255] RGB triplet equivalent of the hexadecimal color code.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
hex + + +string + + + +

the hexadecimal color code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the [0,255] RGB triplet equivalent

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(static) rgb255ToHex(rgb255) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the hexadecimal color code equivalent of the [0, 255] RGB triplet.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb255 + + +Array.<number> + + + +

the [0, 255] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the hexadecimal color code equivalent

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) rgb255ToInt(rgb255) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer equivalent of the [0, 255] RGB triplet.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb255 + + +Array.<number> + + + +

the [0, 255] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the integer equivalent

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(static) rgbToHex(rgb) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the hexadecimal color code equivalent of the [0, 1] RGB triplet.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb + + +Array.<number> + + + +

the [0, 1] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the hexadecimal color code equivalent

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) rgbToInt(rgb) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer equivalent of the [0, 1] RGB triplet.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rgb + + +Array.<number> + + + +

the [0, 1] RGB triplet

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the integer equivalent

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

toString() → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

String representation of the color, i.e. the hexadecimal representation.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the representation.

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/CountdownTimer.html b/docs/CountdownTimer.html new file mode 100644 index 0000000..596e88c --- /dev/null +++ b/docs/CountdownTimer.html @@ -0,0 +1,824 @@ + + + + + + CountdownTimer - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

CountdownTimer

+ + + + + + + +
+ +
+ +

+ util + + CountdownTimer +

+ +

CountdownTimer is a clock counts down from the time of last reset. + + +

+ +
+ +
+ + + + +

Constructor

+ + +

new CountdownTimer(startTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
startTime + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the start time of the countdown

+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

add(deltaTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add more time to the clock's 'start' time (t0).

+

Note: by adding time to t0, you push the current time forward (make it +smaller). As a consequence, getTime() may return a negative number.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
deltaTime + + +number + + + + + + <optional>
+ + + + + +

the time to be added to the clock's start time (t0)

+ + + + + + + + + + + + + + + + + + + + + + + + +

getLastResetTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current offset being applied to the high resolution timebase used by this Clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the offset (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

getTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the time currently left on the countdown.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the time left on the countdown (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

reset(newTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the time on the countdown.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
newTime + + +number + + + + + + <optional>
+ + + + + +

if newTime is undefined, the countdown time is reset to zero, otherwise we set it +to newTime

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/EventEmitter.html b/docs/EventEmitter.html new file mode 100644 index 0000000..c138eec --- /dev/null +++ b/docs/EventEmitter.html @@ -0,0 +1,895 @@ + + + + + + EventEmitter - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

EventEmitter

+ + + + + + + +
+ +
+ +

+ util + + EventEmitter +

+ +

EventEmitter implements the classic observer/observable pattern.

+

Note: this is heavily inspired by http://www.datchley.name/es6-eventemitter/

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new EventEmitter()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
Example
+ +
let observable = new EventEmitter();
+let uuid1 = observable.on('change', data => { console.log(data); });
+observable.emit("change", { a: 1 });
+observable.off("change", uuid1);
+observable.emit("change", { a: 1 });
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

emit(name, data) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Emit an event with a given name and associated data.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

data + + +object + + + +

the data of the event

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

true if at least one listener has been registered for that event, and false otherwise

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

off(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Remove the listener with the given uuid associated to the given event name.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + + + + + + + + + +

on(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Register a new listener for events with the given name emitted by this instance.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)

+
+ + + + + + + + + + + + +

once(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Register a new listener for the given event name, and remove it as soon as the event has been emitted.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)

+
+ + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/EventManager.html b/docs/EventManager.html new file mode 100644 index 0000000..d9ec311 --- /dev/null +++ b/docs/EventManager.html @@ -0,0 +1,2386 @@ + + + + + + EventManager - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

EventManager

+ + + + + + + +
+ +
+ +

+ core + + EventManager +

+ +

This manager handles all participant interactions with the experiment, i.e. keyboard, mouse and touch events.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new EventManager(psychoJS, psychoJS)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +Object + + + +
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static, readonly) _keycodeMap :Object.<number, String>

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map provides support for browsers that have not yet +adopted the W3C KeyboardEvent.code standard for detecting key presses. +It maps the deprecated KeyboardEvent.keycode values to the W3C UI event codes.

+

Unfortunately, it is not very fine-grained: for instance, there is no difference between Alt Left and Alt +Right, or between Enter and Numpad Enter. Use at your own risk (or upgrade your browser...).

+
+ + + +
Type:
+
    +
  • + +Object.<number, String> + + +
  • +
+ + + + + + + + +

(protected, static, readonly) _pygletMap :Object.<String, String>

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates pyglet key names to the corresponding W3C KeyboardEvent codes values.

+

More information can be found here

+
+ + + +
Type:
+
    +
  • + +Object.<String, String> + + +
  • +
+ + + + + + + + +

(protected, static, readonly) _reversePygletMap :Object.<String, String>

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates W3C KeyboardEvent.codes to the corresponding pyglet key names. +

+ + + +
Type:
+
    +
  • + +Object.<String, String> + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(static) keycode2w3c(keycode) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert a keycode to a W3C UI Event code.

+

This is for legacy browsers.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keycode + + +number + + + +

the keycode

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

corresponding W3C UI Event code

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) pyglet2w3c(pygletKeyList) → {Array.string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert a keylist that uses pyglet key names to one that uses W3C KeyboardEvent.code values.

+

This allows key lists that work in the builder environment to work in psychoJS web experiments.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pygletKeyList + + +Array.string + + + +

the array of pyglet key names

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the w3c keyList

+
+ + + +
+
+ Type +
+
+ +Array.string + + +
+
+ + + + + + + + + + +

(static) w3c2pyglet(code) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert a W3C Key Code into a pyglet key.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
code + + +string + + + +

W3C Key Code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

corresponding pyglet key

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(protected) _addKeyListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add key listeners to the document.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addMouseListeners(renderer)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add various mouse listeners to the Pixi renderer of the Window.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
renderer + + +PIXI.Renderer + + + +

The Pixi renderer

+ + + + + + + + + + + + + + + + + + + + + + + + +

clearEvents()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • handle the attribs argument
  • +
+
+ +
+ + + + + +
+

Clear all events from the event buffer.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

clearKeys()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clear all keys from the key buffer.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getKeys(options) → {Array.<string>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the list of keys pressed by the participant.

+

Note: The w3c key-event viewer can be used to see possible values for the items in the keyList given the user's keyboard and chosen layout. The "key" and "code" columns in the UI Events fields are the relevant values for the keyList argument.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
keyList + + +Array.<string> + + + + + + <optional>
+ + + + + +
+ + null + +

keyList allows the user to specify a set of keys to check for. Only keypresses from this set of keys will be removed from the keyboard buffer. If no keyList is given, all keys will be checked and the key buffer will be cleared completely.

timeStamped + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

If true will return a list of tuples instead of a list of keynames. Each tuple has (keyname, time).

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the list of keys that were pressed.

+
+ + + +
+
+ Type +
+
+ +Array.<string> + + +
+
+ + + + + + + + + + +

getMouseInfo() → {EventManager.MouseInfo}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the mouse info.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the mouse info.

+
+ + + +
+
+ Type +
+
+ +EventManager.MouseInfo + + +
+
+ + + + + + + + + + +

resetMoveClock()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • not implemented
  • +
+
+ +
+ + + + + +
+

Reset the move clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

startMoveClock()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • not implemented
  • +
+
+ +
+ + + + + +
+

Start the move clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

stopMoveClock()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • not implemented
  • +
+
+ +
+ + + + + +
+

Stop the move clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + +

ButtonInfo

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pressed + + +Array.number + + + +

the status of each mouse button [left, center, right]: 1 for pressed, 0 for released

clocks + + +Array.Clock + + + +

the clocks associated to the mouse buttons, reset whenever the button is pressed

times + + +Array.number + + + +

the time elapsed since the last rest of the associated clock

+ + + + + + + + + + + + + + + +

MouseInfo

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pos + + +Array.number + + + +

the position of the mouse [x, y]

wheelRel + + +Array.number + + + +

the relative position of the wheel [x, y]

buttons + + +EventManager.ButtonInfo + + + +

the mouse button info

moveClock + + +Clock + + + +

the clock that is reset whenever the mouse moves

+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ExperimentHandler.html b/docs/ExperimentHandler.html new file mode 100644 index 0000000..798c243 --- /dev/null +++ b/docs/ExperimentHandler.html @@ -0,0 +1,2010 @@ + + + + + + ExperimentHandler - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

ExperimentHandler

+ + + + + + + +
+ +
+ +

+ data + + ExperimentHandler +

+ +

An ExperimentHandler keeps track of multiple loops and handlers. It is particularly useful +for generating a single data file from an experiment with many different loops (e.g. interleaved +staircases or loops within loops.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new ExperimentHandler(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

name + + +string + + + +

name of the experiment

extraInfo + + +Object + + + +

additional information, such as session name, participant name, etc.

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Environment :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
SERVER + + +Symbol + + + +
LOCAL + + +Symbol + + + +
+ + + + + + +
+

Experiment environment.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) SaveFormat :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
CSV + + +Symbol + + + +

Results are saved to a .csv file

DATABASE + + +Symbol + + + +

Results are saved to a database

+ + + + + + +
+

Experiment result format

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

_thisEntry

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Legacy experiment getters.

+
+ + + + + + + + + + +

experimentEnded

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Getter for experimentEnded.

+
+ + + + + + + + + + +

experimentEnded

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for experimentEnded.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected, static) _getLoopAttributes(loop)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the attribute names and values for the current trial of a given loop.

+

Only info relating to the trial execution are returned.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loop + + +Object + + + +

the loop

+ + + + + + + + + + + + + + + + + + + + + + + + +

addData(key, value)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add the key/value pair.

+

Multiple key/value pairs can be added to any given entry of the data file. There are +considered part of the same entry until a call to nextEntry is made.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +Object + + + +

the key

value + + +Object + + + +

the value

+ + + + + + + + + + + + + + + + + + + + + + + + +

addLoop(loop)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a loop.

+

The loop might be a TrialHandler, for instance.

+

Data from this loop will be included in the resulting data files.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loop + + +Object + + + +

the loop, e.g. an instance of TrialHandler or StairHandler

+ + + + + + + + + + + + + + + + + + + + + + + + +

isEntryEmpty() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • This really should be renamed: IsCurrentEntryNotEmpty
  • +
+
+ +
+ + + + + +
+

Whether or not the current entry (i.e. trial data) is empty.

+

Note: this is mostly useful at the end of an experiment, in order to ensure that the last entry is saved.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the current entry is empty

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

nextEntry(snapshots)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Inform this ExperimentHandler that the current trial has ended. Further calls to addData +will be associated with the next trial.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
snapshots + + +Object +| + +Array.<Object> +| + +undefined + + + +

array of loop snapshots

+ + + + + + + + + + + + + + + + + + + + + + + + +

removeLoop(loop)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Remove the given loop from the list of unfinished loops, e.g. when it has completed.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loop + + +Object + + + +

the loop, e.g. an instance of TrialHandler or StairHandler

+ + + + + + + + + + + + + + + + + + + + + + + + +

(async) save(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Save the results of the experiment.

+
    +
  • For an experiment running locally, the results are offered for immediate download.
  • +
  • For an experiment running on the server, the results are uploaded to the server.
  • +
+

+

+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
attributes + + +Array.<Object> + + + + + + <optional>
+ + + + + +
+ +

the attributes to be saved

sync + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to communicate with the server in a synchronous manner

tag + + +string + + + + + + <optional>
+ + + + + +
+ + '' + +

an optional tag to add to the filename to which the data is saved (for CSV and XLSX saving options)

clear + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to clear all experiment results immediately after they are saved (this is useful when saving data in separate chunks, throughout an experiment)

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/FaceDetector.html b/docs/FaceDetector.html new file mode 100644 index 0000000..19a3d73 --- /dev/null +++ b/docs/FaceDetector.html @@ -0,0 +1,1744 @@ + + + + + + FaceDetector - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

FaceDetector

+ + + + + + + +
+ +
+ +

+ visual + + FaceDetector +

+ +

This manager handles the detecting of faces in video streams. FaceDetector relies on the +Face-API library developed by +Vincent Muehler.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new FaceDetector(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from the detector

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

input + + +string +| + +HTMLVideoElement +| + +module:visual.Camera + + + + + + + + + + + +

the name of a +movie resource or of a HTMLVideoElement or of a Camera component

faceApiUrl + + +string + + + + + + <optional>
+ + + + + +
+ + 'face-api.js' + +

the Url of the face-api library

modelDir + + +string + + + + + + <optional>
+ + + + + +
+ + 'models' + +

the directory where to find the face detection models

units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the stimulus (e.g. for size, position, vertices)

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the stimulus

units + + +string + + + + + + <optional>
+ + + + + +
+ + 'norm' + +

the units of the stimulus vertices, size and position

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

size + + +number + + + + + + <optional>
+ + + + + +
+ +

the size of the rendered image (the size of the image will be used if size is not specified)

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async, protected) _initFaceApi()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Init the Face-API library.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the visual representation of the detected faces, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

isReady() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Query whether or not the face detector is ready to detect.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the face detector is ready to detect

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

setInput(input, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the video attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
input + + +string +| + +HTMLVideoElement +| + +module:visual.Camera + + + + + + + + + + + +

the name of a +movie resource or a HTMLVideoElement or a Camera component

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

start(period, detectionCallback, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start detecting faces.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
period + + +number + + + + + + + + + + + +

the detection period, in ms (e.g. 100 ms for 10Hz)

detectionCallback + + + + + + + + + +

the callback triggered when detection results are available

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

stop(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop detecting faces.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/FaceDetector_FaceDetector.html b/docs/FaceDetector_FaceDetector.html deleted file mode 100644 index e1af9f4..0000000 --- a/docs/FaceDetector_FaceDetector.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - JSDoc: Class: FaceDetector - - - - - - - - - - -
- -

Class: FaceDetector

- - - - - - -
- -
- -

FaceDetector()

- - -
- -
-
- - - - - - -

new FaceDetector()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- - - - - - - \ No newline at end of file diff --git a/docs/Form.html b/docs/Form.html new file mode 100644 index 0000000..8a19b90 --- /dev/null +++ b/docs/Form.html @@ -0,0 +1,4669 @@ + + + + + + Form - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Form

+ + + + + + + +
+ +
+ +

+ visual + + Form +

+ +

Form stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Form(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the slider

size + + +Array.<number> + + + + + + + + + + + +

the size of the slider, e.g. [1, 0.1] for an horizontal slider

units + + +string + + + + + + <optional>
+ + + + + +
+ + 'height' + +

the units of the Slider position, and font size

color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('LightGray') + +

the color of the slider

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast of the slider

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity of the slider

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth (i.e. the z order), note that the text, radio buttons and slider elements are at depth - 1

items + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [] + +

the array of labels

itemPadding + + +number + + + + + + <optional>
+ + + + + +
+ + 0.05 + +

the granularity

font + + +string + + + + + + <optional>
+ + + + + +
+ + 'Arial' + +

the text font

fontFamily + + +string + + + + + + <optional>
+ + + + + +
+ + 'Helvetica' + +

the text font

bold + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the font of the labels is bold

italic + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the font of the labels is italic

fontSize + + +number + + + + + + <optional>
+ + + + + +
+ +

the font size of the labels (in form units), the default fontSize +depends on the Form units: 14 for 'pix', 0.03 otherwise

clipMask + + +PIXI.Graphics + + + + + + <optional>
+ + + + + +
+ + null + +

the clip mask

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every +frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static, readonly) _defaultItems

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Default form item.

+
+ + + + + + + + + + +

(static, readonly) Layout :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
HORIZONTAL + + +Symbol + + + +
VERTICAL + + +Symbol + + + +
+ + + + + + +
+

Form item layout.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) Types :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
HEADING + + +Symbol + + + +
DESCRIPTION + + +Symbol + + + +
RATING + + +Symbol + + + +
SLIDER + + +Symbol + + + +
FREE_TEXT + + +Symbol + + + +
CHOICE + + +Symbol + + + +
RADIO + + +Symbol + + + +
+ + + + + + +
+

Form item types.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getBoundingBox_px() → {PIXI.Rectangle}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the bounding box in pixel coordinates

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the bounding box, in pixel coordinates

+
+ + + +
+
+ Type +
+
+ +PIXI.Rectangle + + +
+
+ + + + + + + + + + +

(protected) _importItems()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Import the form items from either a spreadsheet resource files (.csv, .xlsx, etc.) or from an array.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _onChange(withPixiopt, withBoundingBoxopt) → {function}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Generate a callback that prepares updates to the stimulus. +This is typically called in the constructor of a stimulus, when attributes are added +with _addAttribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
withPixi + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the PIXI representation must +also be updated

withBoundingBox + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to immediately estimate +the bounding box

+ + + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +function + + +
+
+ + + + + + + + + + +

(protected) _processItems()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Import and process the form items from either a spreadsheet resource files (.csv, .xlsx, etc.) or from an array.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _sanitizeItems()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Sanitize the form items: check that the keys are valid, and fill in default values.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupStimuli()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the stimuli, and the scrollbar.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateDecorations()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the form decorations (bounding box, lines between items, etc.)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the form visual representation, if necessary.

+

This estimate which stimuli are visible, and updates the decorations.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateVisibleStimuli()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the visible stimuli.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addDataToExp(experiment, formatopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add the form data to the given experiment.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
experiment + + +module:data.ExperimentHandler + + + + + + + + + + + +

the experiment into which to insert the form data

format + + +string + + + + + + <optional>
+ + + + + +
+ + 'rows' + +

whether to insert the data as rows or as columns

+ + + + + + + + + + + + + + + + + + + + + + + + +

contains(object, units) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside the bounding box of the stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +string + + + +

the units

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the object is inside the bounding box of the stimulus

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

draw()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Overridden draw that also calls the draw method of all form elements.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

formComplete() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check if the form is complete.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • whether there are any remaining incomplete responses.
  • +
+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

getData() → {object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Collate the questions and responses into a single dataset.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the dataset with all questions and responses.
  • +
+
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + +

hide()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Overridden hide that also calls the hide method of all form elements.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

refresh()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Force a refresh of the stimulus.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

release(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Release the PIXI representation, if there is one.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

reset()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the form.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setAutoDraw(autoDraw, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the autoDraw attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
autoDraw + + +boolean + + + + + + + + + + + +

the new value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setDepth(depth, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the depth attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
depth + + +Array.<number> + + + + + + + + + + + + 0 + +

order in which stimuli is rendered, kind of css's z-index with a negative sign.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setOri(ori, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the orientation attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
ori + + +number + + + + + + + + + + + +

the orientation in degree with 0 as the vertical position, positive values rotate clockwise.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setPos(pos, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the position attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
pos + + +Array.<number> + + + + + + + + + + + +

position of the center of the stimulus, in stimulus units

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setSize(size, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the size attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
size + + +undefined +| + +null +| + +number +| + +Array.<number> + + + + + + + + + + + +

the stimulus size

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/GUI.html b/docs/GUI.html new file mode 100644 index 0000000..aebf661 --- /dev/null +++ b/docs/GUI.html @@ -0,0 +1,2417 @@ + + + + + + GUI - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

GUI

+ + + + + + + +
+ +
+ +

+ core + + GUI +

+ +

GUI manages the various pop-up dialog boxes that guide the participant, throughout the +lifecycle of the experiment, e.g. at the start while the resources are downloading, or at the +end when the data is uploading to the server

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new GUI(psychoJS)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

DEFAULT_SETTINGS :Object

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Default settings for GUI.

+
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(protected, static) _onKeyChange(gui, event)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback triggered upon change event (for required keys).

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
gui + + +module:core.GUI + + + +

this GUI

event + + +Event + + + +

the key's event

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _onCancelExperiment()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback triggered when the participant presses the Cancel button

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _onResourceEvents(signal)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback triggered upon a resource event from the Server Manager.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
signal + + +Object.<string, (string|Symbol)> + + + +

the ServerManager's signal

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _onStartExperiment()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback triggered when the participant presses the OK button

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setProgressMessage(message)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the progress message.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
message + + +string + + + +

the message

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateDialog(changeOKButtonFocusopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the dialog box.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
changeOKButtonFocus + + + + <optional>
+ + + + + +
+ + false + +

whether to change the focus to the OK button

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateProgressBar()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the progress bar.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _userFriendlyError(errorCode) → {Object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the user-friendly html message associated to a pavlovia.or server error code.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
errorCode + + +number + + + +

the pavlovia.org server error code

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

a user-friendly error message

+
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + +

closeDialog()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Close the previously opened dialog box, if there is one.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

dialog(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Show a message to the participant in a dialog box.

+

This function can be used to display both warning and error messages.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
message + + +string + + + + + + + + + + + +

the message to be displayed

error + + +Object.<string, *> + + + + + + + + + + + +

an exception

warning + + +string + + + + + + + + + + + +

a warning message

showOK + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

specifies whether to show the OK button

onOK + + +GUI.onOK + + + + + + <optional>
+ + + + + +
+ +

function called when the participant presses the OK button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

DlgFromDict(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Create a dialog box that (a) enables the participant to set some +experimental values (e.g. the session name), (b) shows progress of resource +download, and (c) enables the participant to cancel the experiment.

+

Setting experiment values

+

DlgFromDict displays an input field for all values in the dictionary. +It is possible to specify default values e.g.:

+let expName = 'stroop';
+let expInfo = {'participant':'', 'session':'01'};
+psychoJS.schedule(psychoJS.gui.DlgFromDict({dictionary: expInfo, title: expName}));
+

If the participant cancels (by pressing Cancel or by closing the dialog box), then +the dictionary remains unchanged.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
logoUrl + + +String + + + + + + <optional>
+ + + + + +
+ +

Url of the experiment logo

text + + +String + + + + + + <optional>
+ + + + + +
+ +

information text

dictionary + + +Object + + + + + + + + + + + +

associative array of values for the participant to set

title + + +String + + + + + + + + + + + +

name of the project

requireParticipantClick + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether the participant must click on the OK +button, when it becomes enabled, to move on with the experiment

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

finishDialog(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Create a dialog box with a progress bar, to inform the participant of +the last stages of the experiment: upload of results, of log, and closing +of session.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
text + + +String + + + + + + <optional>
+ + + + + +

information text

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + + + + +

onOK()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/GratingStim.html b/docs/GratingStim.html new file mode 100644 index 0000000..602e4e2 --- /dev/null +++ b/docs/GratingStim.html @@ -0,0 +1,3195 @@ + + + + + + GratingStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

GratingStim

+ + + + + + + +
+ +
+ +

+ visual + + GratingStim +

+ +

Grating Stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new GratingStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +Window + + + + + + + + + + + +

the associated Window

tex + + +String +| + +HTMLImageElement + + + + + + <optional>
+ + + + + +
+ + "sin" + +

the name of the predefined grating texture or image resource or the HTMLImageElement corresponding to the texture

mask + + +String +| + +HTMLImageElement + + + + + + <optional>
+ + + + + +
+ +

the name of the mask resource or HTMLImageElement corresponding to the mask

units + + +String + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the stimulus (e.g. for size, position, vertices)

sf + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

spatial frequency of the function used in grating stimulus

phase + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

phase of the function used in grating stimulus, multiples of period of that function

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the stimulus

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

size + + +number + + + + + + <optional>
+ + + + + +
+ +

the size of the rendered image (DEFAULT_STIM_SIZE_PX will be used if size is not specified)

color + + +Color + + + + + + <optional>
+ + + + + +
+ + "white" + +

Foreground color of the stimulus. Can be String like "red" or "#ff0000" or Number like 0xff0000.

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

Set the opacity of the stimulus. Determines how visible the stimulus is relative to background.

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

Set the contrast of the stimulus, i.e. scales how far the stimulus deviates from the middle grey. Ranges [-1, 1].

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth (i.e. the z order)

interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

Whether to interpolate (linearly) the texture in the stimulus. Currently supports only image based gratings.

blendmode + + +String + + + + + + <optional>
+ + + + + +
+ + "avg" + +

blend mode of the stimulus, determines how the stimulus is blended with the background. Supported values: "avg", "add", "mul", "screen".

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getDisplaySize() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the size of the display image, which is either that of the GratingStim or that of the image +it contains.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the size of the displayed image

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _getPixiMeshFromPredefinedShaders(shaderName, uniforms) → {Pixi.Mesh}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Generate PIXI.Mesh object based on provided shader function name and uniforms.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
shaderName + + +String + + + +

name of the shader. Must be one of the SHADERS

uniforms + + +Object + + + +

a set of uniforms to supply to the shader. Mixed together with default uniform values.

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

Pixi.Mesh object that represents shader and later added to the scene.

+
+ + + +
+
+ Type +
+
+ +Pixi.Mesh + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setBlendmode(blendMode, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set blend mode of the grating stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
blendMode + + +String + + + + + + + + + + + + avg + +

blend mode, can be one of the following: ["avg", "add", "mul", "screen"].

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setColor(colorVal, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set foreground color value for the grating stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
colorVal + + +Color + + + + + + + + + + + + white + +

color value, can be String like "red" or "#ff0000" or Number like 0xff0000.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setColorSpace(colorSpaceVal, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set color space value for the grating stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
colorSpaceVal + + +String + + + + + + + + + + + + RGB + +

color space value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setInterpolate(interpolate, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Whether to interpolate (linearly) the texture in the stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
interpolate + + +boolean + + + + + + + + + + + + false + +

interpolate or not.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setMask(mask, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the mask attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
mask + + +HTMLImageElement +| + +string + + + + + + + + + + + +

the name of the mask resource or HTMLImageElement corresponding to the mask

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setOpacity(opacityopt, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determines how visible the stimulus is relative to background.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1 + +

opacity - The value should be a single float ranging 1.0 (opaque) to 0.0 (transparent).

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setPhase(phase, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set phase value for the function.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
phase + + +number + + + + + + + + + + + +

phase value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setSF(sf, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set spatial frequency value for the function.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
sf + + +number + + + + + + + + + + + +

spatial frequency value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setTex(tex, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the tex attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
tex + + +HTMLImageElement +| + +string + + + + + + + + + + + +

the name of built in shader function or name of the image resource or HTMLImageElement corresponding to the image

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ImageStim.html b/docs/ImageStim.html new file mode 100644 index 0000000..e992fd4 --- /dev/null +++ b/docs/ImageStim.html @@ -0,0 +1,1899 @@ + + + + + + ImageStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

ImageStim

+ + + + + + + +
+ +
+ +

+ visual + + ImageStim +

+ +

Image Stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new ImageStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
    + +
  • ColorMixin
  • + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +Window + + + + + + + + + + + +

the associated Window

image + + +string +| + +HTMLImageElement + + + + + + + + + + + +

the name of the image resource or the HTMLImageElement corresponding to the image

mask + + +string +| + +HTMLImageElement + + + + + + + + + + + +

the name of the mask resource or HTMLImageElement corresponding to the mask

units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the stimulus (e.g. for size, position, vertices)

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the stimulus

units + + +string + + + + + + <optional>
+ + + + + +
+ + 'norm' + +

the units of the stimulus vertices, size and position

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

size + + +number + + + + + + <optional>
+ + + + + +
+ +

the size of the rendered image (the size of the image will be used if size is not specified)

color + + +Color + + + + + + <optional>
+ + + + + +
+ + 'white' + +

the background color

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth (i.e. the z order)

texRes + + +number + + + + + + <optional>
+ + + + + +
+ + 128 + +

the resolution of the text

interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the image is interpolated

flipHoriz + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip horizontally

flipVert + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip vertically

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getDisplaySize() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the size of the display image, which is either that of the ImageStim or that of the image +it contains.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the size of the displayed image

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setImage(image, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the image attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
image + + +HTMLImageElement +| + +string + + + + + + + + + + + +

the name of the image resource or HTMLImageElement corresponding to the image

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setInterpolate(interpolate, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Whether to interpolate (linearly) the texture in the stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
interpolate + + +boolean + + + + + + + + + + + + false + +

interpolate or not.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setMask(mask, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the mask attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
mask + + +HTMLImageElement +| + +string + + + + + + + + + + + +

the name of the mask resource or HTMLImageElement corresponding to the mask

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/KeyPress.html b/docs/KeyPress.html new file mode 100644 index 0000000..d6ee0b2 --- /dev/null +++ b/docs/KeyPress.html @@ -0,0 +1,301 @@ + + + + + + KeyPress - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

KeyPress

+ + + + + + + +
+ +
+ +

+ core + + KeyPress +

+ +

<pKeyPress holds information about a key that has been pressed, such as the duration of the press.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new KeyPress(code, tDown, name)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
code + + +string + + + +

W3C Key Code

tDown + + +number + + + +

time of key press (keydown event) relative to the global Monotonic Clock

name + + +string +| + +undefined + + + +

pyglet key name

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Keyboard.html b/docs/Keyboard.html new file mode 100644 index 0000000..3ea6f5d --- /dev/null +++ b/docs/Keyboard.html @@ -0,0 +1,1793 @@ + + + + + + Keyboard - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Keyboard

+ + + + + + + +
+ +
+ +

+ core + + Keyboard +

+ +

This manager handles all keyboard events. It is a substitute for the keyboard component of EventManager.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Keyboard(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

bufferSize + + +number + + + + + + <optional>
+ + + + + +
+ + 10000 + +

the maximum size of the circular keyboard event buffer

waitForStart + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to wait for a call to module:core.Keyboard#start +before recording keyboard events

clock + + +Clock + + + + + + <optional>
+ + + + + +
+ +

an optional clock

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) KeyStatus :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
KEY_DOWN + + +Symbol + + + +
KEY_UP + + +Symbol + + + +
+ + + + + + +
+

Keyboard KeyStatus.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(static) includes(keypressList, keyName) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Test whether a list of KeyPress's contains one with a particular name.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
keypressList + + +Array.<module:core.KeyPress> + + + +

list of KeyPress's

keyName + + +string + + + +

pyglet key name, e.g. 'escape', 'left'

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not a KeyPress with the given pyglet key name is present in the list

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

(protected) _addKeyListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add key listeners to the document.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

clearEvents()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clear all events and resets the circular buffers.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getEvents() → {Array.<Keyboard.KeyEvent>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the list of those keyboard events still in the buffer, i.e. those that have not been +previously cleared by calls to getKeys with clear = true.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the list of events still in the buffer

+
+ + + +
+
+ Type +
+
+ +Array.<Keyboard.KeyEvent> + + +
+
+ + + + + + + + + + +

getKeys(options) → {Array.<KeyPress>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the list of keys pressed or pushed by the participant.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
keyList + + +Array.<string> + + + + + + <optional>
+ + + + + +
+ + [] + +

the list of keys to consider. If keyList is empty, we consider all keys. +Note that we use pyglet keys here, to make the PsychoJs code more homogeneous with PsychoPy.

waitRelease + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to include those keys pressed but not released. If +waitRelease = false, key presses without a corresponding key release will have an undefined duration.

clear + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to keep in the buffer the key presses or pushes for a subsequent call to getKeys. If a keyList has been given and clear = true, we only remove from the buffer those keys in keyList

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the list of keys that were pressed (keydown followed by keyup) or pushed +(keydown with no subsequent keyup at the time getKeys is called).

+
+ + + +
+
+ Type +
+
+ +Array.<KeyPress> + + +
+
+ + + + + + + + + + +

start()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start recording keyboard events.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

stop()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop recording keyboard events.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + +

KeyEvent

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
W3C + + +string + + + +

key code

W3C + + +string + + + +

key

pyglet + + +string + + + +

key

key + + +module:core.Keyboard#KeyStatus + + + +

status

timestamp + + +number + + + +

(in seconds)

+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Logger.html b/docs/Logger.html new file mode 100644 index 0000000..cd40f2f --- /dev/null +++ b/docs/Logger.html @@ -0,0 +1,2177 @@ + + + + + + Logger - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Logger

+ + + + + + + +
+ +
+ +

+ core + + Logger +

+ +

This class handles a variety of loggers, e.g. a browser console one (mostly for debugging), +a remote one, etc.

+

Note: we use log4javascript for the console logger, and our own for the server logger.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Logger(psychoJS, threshold)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

threshold + + +* + + + +

the logging threshold, e.g. log4javascript.Level.ERROR

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static, readonly) _ServerLevelValue :number

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
CRITICAL + + +number + + + +
ERROR + + +number + + + +
WARNING + + +number + + + +
DATA + + +number + + + +
EXP + + +number + + + +
INFO + + +number + + + +
DEBUG + + +number + + + +
NOTSET + + +number + + + +
+ + + + + + +
+

Server logging level values.

+

We use those values to determine whether a log is to be sent to the server or not.

+
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + + + + +

(static, readonly) ServerLevel :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
CRITICAL + + +Symbol + + + +
ERROR + + +Symbol + + + +
WARNING + + +Symbol + + + +
DATA + + +Symbol + + + +
EXP + + +Symbol + + + +
INFO + + +Symbol + + + +
DEBUG + + +Symbol + + + +
NOTSET + + +Symbol + + + +
+ + + + + + +
+

Server logging level.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(protected) _customConsoleLayout() → {*}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Create a custom console layout.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the custom layout

+
+ + + +
+
+ Type +
+
+ +* + + +
+
+ + + + + + + + + + +

(protected) _getValue(level) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the integer value associated with a logging level.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
level + + +module:core.Logger.ServerLevel + + + +

the logging level

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the value associated with the logging level, or 30 is the logging level is unknown.
  • +
+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected) _throttle(time) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check whether or not a log messages must be throttled.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
time + + +number + + + +

the time of the latest log message

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not to log the message

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

data(msg, timeopt, objopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Log a server message at the DATA level.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
msg + + +string + + + + + + + + + +

the message to be logged.

time + + +number + + + + + + <optional>
+ + + + + +

the logging time

obj + + +object + + + + + + <optional>
+ + + + + +

the associated object (e.g. a Trial)

+ + + + + + + + + + + + + + + + + + + + + + + + +

exp(msg, timeopt, objopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Log a server message at the EXP level.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
msg + + +string + + + + + + + + + +

the message to be logged.

time + + +number + + + + + + <optional>
+ + + + + +

the logging time

obj + + +object + + + + + + <optional>
+ + + + + +

the associated object (e.g. a Trial)

+ + + + + + + + + + + + + + + + + + + + + + + + +

(async) flush()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Flush all server logs to the server.

+

Note: the logs are compressed using Pako's zlib algorithm. +See https://github.com/nodeca/pako for details.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

log(msg, level, timeopt, objopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Log a server message.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
msg + + +string + + + + + + + + + +

the message to be logged.

level + + +module:core.Logger.ServerLevel + + + + + + + + + +

logging level

time + + +number + + + + + + <optional>
+ + + + + +

the logging time

obj + + +object + + + + + + <optional>
+ + + + + +

the associated object (e.g. a Trial)

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLevel(serverLevel)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Change the logging level.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
serverLevel + + +module:core.Logger.ServerLevel + + + +

the new logging level

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Microphone.html b/docs/Microphone.html new file mode 100644 index 0000000..6a807aa --- /dev/null +++ b/docs/Microphone.html @@ -0,0 +1,1946 @@ + + + + + + Microphone - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Microphone

+ + + + + + + +
+ +
+ +

+ sound + + Microphone +

+ +

This manager handles the recording of audio signal.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Microphone(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
win + + +module:core.Window + + + + + + + + + + + +

the associated Window

name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

format + + +string + + + + + + <optional>
+ + + + + +
+ + 'audio/webm;codecs=opus' + +

the format for the audio file

sampleRateHz + + +number + + + + + + <optional>
+ + + + + +
+ + 48000 + +

the audio sampling rate, in Hz

clock + + +Clock + + + + + + <optional>
+ + + + + +
+ +

an optional clock

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _onChange()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback for changes to the recording settings.

+

Changes to the settings require the recording to stop and be re-started.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async, protected) _prepareRecording()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prepare the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

download(filename)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Offer the audio recording to the participant as a sound file to download.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
filename + + +string + + + + + + audio.webm + +

the filename

+ + + + + + + + + + + + + + + + + + + + + + + + +

flush() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to flush the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the data has actually been made available

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

(async) getRecording(tag, flushopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current audio recording as an AudioClip in the given format.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
tag + + +string + + + + + + + + + + + +

an optional tag for the audio clip

flush + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to first flush the recording

+ + + + + + + + + + + + + + + + + + + + + + + + +

pause() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to pause the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually paused

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

resume(options) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to resume the recording.

+

resume has no effect if the recording was not previously paused.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
clear + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to empty the audio buffer before +resuming the recording

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually resumed

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

start() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to start the recording.

+

Note that it typically takes 50ms-200ms for the recording to actually starts once +a request to start has been submitted.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually started

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

stop(options) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to stop the recording.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
filename + + +string + + + + + + <optional>
+ + + + + +

the name of the file to which the audio recording will be +saved

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually stopped, and the recorded +data was made available

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

(async) upload(tag)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Upload the audio recording to the pavlovia server.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tag + + +string + + + +

an optional tag for the audio file

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/MinimalStim.html b/docs/MinimalStim.html new file mode 100644 index 0000000..f4dd821 --- /dev/null +++ b/docs/MinimalStim.html @@ -0,0 +1,1213 @@ + + + + + + MinimalStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

MinimalStim

+ + + + + + + +
+ +
+ +

+ core + + MinimalStim +

+ +

MinimalStim is the base class for all stimuli.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new MinimalStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + win.autoLog + +

whether to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(abstract, protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+

Note: this is an abstract function, which should not be called.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) contains(object, units)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside this stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +String + + + +

the stimulus units

+ + + + + + + + + + + + + + + + + + + + + + + + +

draw()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Draw this stimulus on the next frame draw.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

hide()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Hide this stimulus on the next frame draw.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

release(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Release the PIXI representation, if there is one.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setAutoDraw(autoDraw, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the autoDraw attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
autoDraw + + +boolean + + + + + + + + + + + +

the new value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/MonotonicClock.html b/docs/MonotonicClock.html new file mode 100644 index 0000000..0ebd80e --- /dev/null +++ b/docs/MonotonicClock.html @@ -0,0 +1,987 @@ + + + + + + MonotonicClock - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

MonotonicClock

+ + + + + + + +
+ +
+ +

+ util + + MonotonicClock +

+ +

MonotonicClock offers a convenient way to keep track of time during experiments. An experiment can have as many independent clocks as needed, e.g. one to time responses, another one to keep track of stimuli, etc.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new MonotonicClock(startTimeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
startTime + + +number + + + + + + <optional>
+ + + + + +
+ + <time elapsed since the reference point, i.e. the time when the module was loaded> + +

the clock's start time (in ms)

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static) _referenceTime :number

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

The clock's referenceTime is the time when the module was loaded (in seconds).

+
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(static) getDate(locales, options) → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current timestamp with language-sensitive formatting rules applied.

+

Note: This is just a convenience wrapper around `Intl.DateTimeFormat()`.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
locales + + +string +| + +array.string + + + + + + en-CA + +

A string with a BCP 47 language tag, or an array of such strings.

options + + +object + + + + + +

An object with detailed date and time styling information.

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

The current timestamp in the chosen format.

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) getDateStr() → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the clock's current time in the default format filtering out file name unsafe characters.

+

Note: This is mostly used as an appendix to the name of the keys save to the server.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

A string representing the current time formatted as YYYY-MM-DD_HH[h]mm.ss.sss

+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) getReferenceTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the time elapsed since the reference point.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the time elapsed since the reference point (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

getLastResetTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current offset being applied to the high resolution timebase used by this Clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the offset (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

getTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current time on this clock.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the current time (in seconds)

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Mouse.html b/docs/Mouse.html new file mode 100644 index 0000000..7c2923a --- /dev/null +++ b/docs/Mouse.html @@ -0,0 +1,1757 @@ + + + + + + Mouse - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Mouse

+ + + + + + + +
+ +
+ +

+ core + + Mouse +

+ +

This manager handles the interactions between the experiment's stimuli and the mouse.

+

Note: the unit of Mouse is that of its associated Window.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Mouse(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • visible is not handled at the moment (mouse is always visible)
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +Window + + + + + + + + + + + +

the associated Window

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

clickReset(buttonsopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the clocks associated to the given mouse buttons.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
buttons + + +Array.number + + + + + + <optional>
+ + + + + +
+ + [0,1,2] + +

the buttons to reset (0: left, 1: center, 2: right)

+ + + + + + + + + + + + + + + + + + + + + + + + +

getPos() → {Array.number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current position of the mouse in mouse/Window units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the position of the mouse in mouse/Window units

+
+ + + +
+
+ Type +
+
+ +Array.number + + +
+
+ + + + + + + + + + +

getPressed(getTimeopt) → {Array.number|Array.<Array.number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the status of each button (pressed or released) and, optionally, the time elapsed between the last call to clickReset and the pressing or releasing of the buttons.

+

Note: clickReset is typically called at stimulus onset. When the participant presses a button, the time elapsed since the clickReset is stored internally and can be accessed any time afterwards with getPressed.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
getTime + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to also return timestamps

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

either an array of size 3 with the status (1 for pressed, 0 for released) of each mouse button [left, center, right], or a tuple with that array and another array of size 3 with the timestamps.

+
+ + + +
+
+ Type +
+
+ +Array.number +| + +Array.<Array.number> + + +
+
+ + + + + + + + + + +

getRel() → {Array.number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the position of the mouse relative to that at the last call to getRel +or getPos, in mouse/Window units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the relation position of the mouse in mouse/Window units.

+
+ + + +
+
+ Type +
+
+ +Array.number + + +
+
+ + + + + + + + + + +

getWheelRel() → {Array.number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the travel of the mouse scroll wheel since the last call to getWheelRel.

+

Note: Even though this method returns a [x, y] array, for most wheels/systems y is the only +value that varies.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the mouse scroll wheel travel

+
+ + + +
+
+ Type +
+
+ +Array.number + + +
+
+ + + + + + + + + + +

isPressedIn(shape, buttonsopt, optionsopt) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Helper method for checking whether a stimulus has had any button presses within bounds.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
shape + + +object +| + +module:visual.VisualStim + + + + + + + + + +

A type of visual stimulus or object having a contains() method.

buttons + + +object +| + +number + + + + + + <optional>
+ + + + + +

The target button index potentially tucked inside an object.

options + + +object + + + + + + <optional>
+ + + + + +
+
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
shape + + +object +| + +module:visual.VisualStim + + + + + + <optional>
+ + + + + +
buttons + + +number + + + + + + <optional>
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

Whether button pressed is contained within stimulus.

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

mouseMoved(distanceopt, resetopt) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether the mouse has moved beyond a certain distance.

+

distance +

    +
  • mouseMoved() or mouseMoved(undefined, false): determine whether the mouse has moved at all since the last +call to getPos
  • +
  • mouseMoved(distance: number, false): determine whether the mouse has travelled further than distance, in terms of line of sight
  • +
  • mouseMoved(distance: [number,number], false): determine whether the mouse has travelled horizontally or vertically further then the given horizontal and vertical distances
  • +

+

reset +

    +
  • mouseMoved(distance, true): reset the mouse move clock, return false
  • +
  • mouseMoved(distance, 'here'): return false
  • +
  • mouseMoved(distance, [x: number, y: number]: artifically set the previous mouse position to the given coordinates and determine whether the mouse moved further than the given distance
  • +

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
distance + + +undefined +| + +number +| + +Array.number + + + + + + <optional>
+ + + + + +
+ +

the distance to which the mouse movement is compared (see above for a full description)

reset + + +boolean +| + +String +| + +Array.number + + + + + + <optional>
+ + + + + +
+ + false + +

see above for a full description

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

see above for a full description

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

mouseMoveTime() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the amount of time elapsed since the last mouse movement.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the time elapsed since the last mouse movement

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/MovieStim.html b/docs/MovieStim.html new file mode 100644 index 0000000..3046a12 --- /dev/null +++ b/docs/MovieStim.html @@ -0,0 +1,2363 @@ + + + + + + MovieStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

MovieStim

+ + + + + + + +
+ +
+ +

+ visual + + MovieStim +

+ +

Movie Stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new MovieStim(options, movie)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • autoPlay does not work for the moment.
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
options + + +Object + + + + + + + + + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + +

the associated Window

+ +
movie + + +string +| + +HTMLVideoElement +| + +module:visual.Camera + + + + + + + + + + + +

the name of a +movie resource or of a HTMLVideoElement or of a Camera component

options.units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the stimulus (e.g. for size, position, vertices)

options.pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the stimulus

options.units + + +string + + + + + + <optional>
+ + + + + +
+ + 'norm' + +

the units of the stimulus vertices, size and position

options.ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

options.size + + +number + + + + + + <optional>
+ + + + + +
+ +

the size of the rendered image (the size of the image will be used if size is not specified)

options.color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('white') + +

the background color

options.opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

options.contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

options.interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the image is interpolated

options.flipHoriz + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip horizontally

options.flipVert + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip vertically

options.loop + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to loop the movie

options.volume + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the volume of the audio track (must be between 0.0 and 1.0)

options.noAudio + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to play the audio

options.autoPlay + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to autoplay the video

options.autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

options.autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getDisplaySize() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the size of the display image, which is either that of the ImageStim or that of the image +it contains.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the size of the displayed image

+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

pause(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Pause the movie.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

play(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the movie.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

reset(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

seek(timePoint, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Jump to a specific timepoint

+

Note: seek is experimental and does not work on all browsers at the moment.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
timePoint + + +number + + + + + + + + + + + +

the timepoint to which to jump (in second)

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setMovie(movie, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the movie attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
movie + + +string +| + +HTMLVideoElement +| + +module:visual.Camera + + + + + + + + + + + +

the name of a +movie resource or of a HTMLVideoElement or of a Camera component

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

stop(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop the movie and reset to 0s.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/MultiStairHandler.html b/docs/MultiStairHandler.html new file mode 100644 index 0000000..137f7ad --- /dev/null +++ b/docs/MultiStairHandler.html @@ -0,0 +1,1410 @@ + + + + + + MultiStairHandler - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

MultiStairHandler

+ + + + + + + +
+ +
+ +

+ data + + MultiStairHandler +

+ +

A handler dealing with multiple staircases, simultaneously.

+

Note that, at the moment, using the MultiStairHandler requires the jsQuest.js +library to be loaded as a resource, at the start of the experiment.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new MultiStairHandler(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + +

the handler options

+
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

varName + + +string + + + + + + + + + + + +

the name of the variable / intensity / contrast +/ threshold manipulated by the staircases

stairType + + +MultiStairHandler.StaircaseType + + + + + + <optional>
+ + + + + +
+ + "simple" + +

the +handler type

conditions + + +Array.<Object> +| + +String + + + + + + <optional>
+ + + + + +
+ + [undefined] + +

if it is a string, +we treat it as the name of a conditions resource

method + + +module:data.TrialHandler.Method + + + + + + + + + + + +

the trial method

nTrials + + +number + + + + + + <optional>
+ + + + + +
+ + 50 + +

maximum number of trials

randomSeed + + +number + + + + + + + + + + + +

seed for the random number generator

name + + +string + + + + + + + + + + + +

name of the handler

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • TrialHandler
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) StaircaseStatus :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
RUNNING + + +Symbol + + + +

The staircase is currently running.

FINISHED + + +Symbol + + + +

The staircase is now finished.

+ + + + + + +
+

Staircase status.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) StaircaseType :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
SIMPLE + + +Symbol + + + +

Simple staircase handler.

QUEST + + +Symbol + + + +

QUEST handler.

+ + + + + + +
+

MultiStairHandler staircase type.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

currentStaircase

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current staircase.

+
+ + + + + + + + + + +

intensity

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current intensity.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _nextTrial()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Move onto the next trial.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _prepareStaircases()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the staircases, according to the conditions.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _validateConditions()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Validate the conditions.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addResponse()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a response to the current staircase.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Polygon.html b/docs/Polygon.html new file mode 100644 index 0000000..fe2dfb5 --- /dev/null +++ b/docs/Polygon.html @@ -0,0 +1,2125 @@ + + + + + + Polygon - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Polygon

+ + + + + + + +
+ +
+ +

+ visual + + Polygon +

+ +

Polygonal visual stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Polygon(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Polygonal visual stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +Window + + + + + + + + + + + +

the associated Window

lineWidth + + +number + + + + + + <optional>
+ + + + + +
+ + 1.5 + +

the line width

lineColor + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('white') + +

the line color

fillColor + + +Color + + + + + + + + + + + +

the fill color

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

edges + + +number + + + + + + <optional>
+ + + + + +
+ + 3 + +

the number of edges of the polygon

radius + + +number + + + + + + <optional>
+ + + + + +
+ + 0.5 + +

the radius of the polygon

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position

size + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the size

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

units + + +string + + + + + + + + + + + +

the units of the stimulus vertices, size and position

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth

interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the shape is interpolated

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getPixiPolygon() → {Object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the PIXI polygon (in pixel units) corresponding to the vertices.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the PIXI polygon corresponding to this stimulus vertices.

+
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + +

(protected) _getVertices_px() → {Array.<Array.<number>>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the vertices in pixel units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the vertices (in pixel units)

+
+ + + +
+
+ Type +
+
+ +Array.<Array.<number>> + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

contains(object, units) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside the bounding box of the ShapeStim.

+

This is overridden in order to provide a finer inclusion test.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +string + + + +

the units

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the object is inside the bounding box of the ShapeStim

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

setEdges(edges, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the edges attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
edges + + +number + + + + + + + + + + + +

the number of edges

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setRadius(radius, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the radius attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
radius + + +number + + + + + + + + + + + +

the polygon radius

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setVertices(vertices, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the vertices attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
vertices + + +Array.<Array.<number>> + + + + + + + + + + + +

the vertices

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/QuestHandler.html b/docs/QuestHandler.html new file mode 100644 index 0000000..453461e --- /dev/null +++ b/docs/QuestHandler.html @@ -0,0 +1,2262 @@ + + + + + + QuestHandler - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

QuestHandler

+ + + + + + + +
+ +
+ +

+ data + + QuestHandler +

+ +

A Trial Handler that implements the Quest algorithm for quick measurement of + psychophysical thresholds. QuestHandler relies on the jsQuest library, a port of Prof Dennis Pelli's QUEST algorithm by Daiichiro Kuroki.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new QuestHandler(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + +

the handler options

+
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

varName + + +string + + + + + + + + + + + +

the name of the variable / intensity / contrast / threshold manipulated by QUEST

startVal + + +number + + + + + + + + + + + +

initial guess for the threshold

startValSd + + +number + + + + + + + + + + + +

standard deviation of the initial guess

minVal + + +number + + + + + + + + + + + +

minimum value for the threshold

maxVal + + +number + + + + + + + + + + + +

maximum value for the threshold

pThreshold + + +number + + + + + + <optional>
+ + + + + +
+ + 0.82 + +

threshold criterion expressed as probability of getting a correct response

nTrials + + +number + + + + + + + + + + + +

maximum number of trials

stopInterval + + +number + + + + + + + + + + + +

minimum [5%, 95%] confidence interval required for the loop to stop

method + + +QuestHandler.Method + + + + + + + + + + + +

the QUEST method

beta + + +number + + + + + + <optional>
+ + + + + +
+ + 3.5 + +

steepness of the QUEST psychometric function

delta + + +number + + + + + + <optional>
+ + + + + +
+ + 0.01 + +

fraction of trials with blind responses

gamma + + +number + + + + + + <optional>
+ + + + + +
+ + 0.5 + +

fraction of trails that would generate a correct response when the threshold is infinitely small

grain + + +number + + + + + + <optional>
+ + + + + +
+ + 0.01 + +

quantization of the internal table

name + + +string + + + + + + + + + + + +

name of the handler

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • TrialHandler
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Method :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
QUANTILE + + +Symbol + + + +

Quantile threshold estimate.

MEAN + + +Symbol + + + +

Mean threshold estimate.

MODE + + +Symbol + + + +

Mode threshold estimate.

+ + + + + + +
+

QuestHandler method

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

intensity

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current value of the variable / contrast / threshold.

+

This is the getter associated to getQuestValue.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateQuestValue()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the next value of the QUEST variable, based on the current value +and on the selected QUEST method.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupJsQuest()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the JS Quest object.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addResponse()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a response and update the PDF.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

confInterval()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get an estimate of the 5%-95% confidence interval (CI).

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getQuestValue() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current value of the variable / contrast / threshold.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the current QUEST value for the variable / contrast / threshold

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

mean() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the mean of the Quest posterior PDF.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the mean

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

mode() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the mode of the Quest posterior PDF.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the mode

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

quantile() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the standard deviation of the Quest posterior PDF.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the quantile

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

sd() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the standard deviation of the Quest posterior PDF.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the standard deviation

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

setMethod(method, log)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the method attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
method + + +mixed + + + +

the method value, PsychoPy-style values ("mean", "median", +"quantile") are converted to their respective QuestHandler.Method values

log + + +boolean + + + +

whether or not to log the change of seed

+ + + + + + + + + + + + + + + + + + + + + + + + +

simulate()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Simulate a response.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Rect.html b/docs/Rect.html new file mode 100644 index 0000000..d803f78 --- /dev/null +++ b/docs/Rect.html @@ -0,0 +1,2214 @@ + + + + + + Rect - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Rect

+ + + + + + + +
+ +
+ +

+ visual + + Rect +

+ +

Rectangular visual stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Rect(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

lineWidth + + +number + + + + + + <optional>
+ + + + + +
+ + 1.5 + +

the line width

lineColor + + +Color + + + + + + <optional>
+ + + + + +
+ + 'white' + +

the line color

fillColor + + +Color + + + + + + <optional>
+ + + + + +
+ +

the fill color

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

width + + +number + + + + + + <optional>
+ + + + + +
+ + 0.5 + +

the width of the rectangle

height + + +number + + + + + + <optional>
+ + + + + +
+ + 0.5 + +

the height of the rectangle

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position

size + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the size

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

units + + +string + + + + + + <optional>
+ + + + + +
+ + "height" + +

the units of the stimulus vertices, size and position

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth

interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the shape is interpolated

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getPixiPolygon() → {Object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the PIXI polygon (in pixel units) corresponding to the vertices.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the PIXI polygon corresponding to this stimulus vertices.

+
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + +

(protected) _getVertices_px() → {Array.<Array.<number>>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the vertices in pixel units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the vertices (in pixel units)

+
+ + + +
+
+ Type +
+
+ +Array.<Array.<number>> + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateVertices()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the vertices.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

contains(object, units) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + +
Inherited From:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside the bounding box of the ShapeStim.

+

This is overridden in order to provide a finer inclusion test.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +string + + + +

the units

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the object is inside the bounding box of the ShapeStim

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

setHeight(height, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the height attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
height + + +number + + + + + + + + + + + +

the rectangle height

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setVertices(vertices, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the vertices attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
vertices + + +Array.<Array.<number>> + + + + + + + + + + + +

the vertices

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setWidth(width, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the width attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
width + + +number + + + + + + + + + + + +

the rectangle width

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Scheduler.html b/docs/Scheduler.html new file mode 100644 index 0000000..c7a90d7 --- /dev/null +++ b/docs/Scheduler.html @@ -0,0 +1,1478 @@ + + + + + + Scheduler - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Scheduler

+ + + + + + + +
+ +
+ +

+ util + + Scheduler +

+ +

A scheduler helps run the main loop by managing scheduled functions, +called tasks, after each frame is displayed.

+

+Tasks are either another Scheduler, or a +JavaScript functions returning one of the following codes: +

    +
  • Scheduler.Event.NEXT: Move onto the next task *without* rendering the scene first.
  • +
  • Scheduler.Event.FLIP_REPEAT: Render the scene and repeat the task.
  • +
  • Scheduler.Event.FLIP_NEXT: Render the scene and move onto the next task.
  • +
  • Scheduler.Event.QUIT: Quit the scheduler.
  • +
+

+

It is possible to create sub-schedulers, e.g. to handle loops. +Sub-schedulers are added to a parent scheduler as a normal +task would be by calling scheduler.add(subScheduler).

+

Conditional branching is also available: +scheduler.addConditionalBranches

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Scheduler(psychoJS)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
psychoJS + + +module:core.PsychoJS + + + +

the PsychoJS instance

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Event :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
NEXT + + +Symbol + + + +

Move onto the next task without rendering the scene first.

FLIP_REPEAT + + +Symbol + + + +

Render the scene and repeat the task.

FLIP_NEXT + + +Symbol + + + +

Render the scene and move onto the next task.

QUIT + + +Symbol + + + +

Quit the scheduler.

+ + + + + + +
+

Events.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) Status :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
RUNNING + + +Symbol + + + +

The Scheduler is running.

STOPPED + + +Symbol + + + +

The Scheduler is stopped.

+ + + + + + +
+

Status.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

status

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the status of the scheduler.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

add(task, …args)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Schedule a new task.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
task + + +Scheduler~Task +| + +Scheduler + + + + + + + + + +

the task to be scheduled

args + + +* + + + + + + + + + + <repeatable>
+ +

arguments for that task

+ + + + + + + + + + + + + + + + + + + + + + + + +

addConditional(condition, thenScheduler, elseScheduler)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Schedule a series of task or another, based on a condition.

+

Note: the tasks are sub-schedulers.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
condition + + +Scheduler~Condition + + + +

the condition

thenScheduler + + +Scheduler + + + +

the Scheduler to be run if the condition is satisfied

elseScheduler + + +Scheduler + + + +

the Scheduler to be run if the condition is not satisfied

+ + + + + + + + + + + + + + + + + + + + + + + + +

(async) start()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start this scheduler.

+

Note: tasks are run after each animation frame.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

stop()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop this scheduler.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + + + + +

Condition() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Condition evaluated when the task is run.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

Task(argsopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Task to be run by the scheduler.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
args + + +* + + + + + + <optional>
+ + + + + +

optional arguments

+ + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ServerManager.html b/docs/ServerManager.html new file mode 100644 index 0000000..7f35f0d --- /dev/null +++ b/docs/ServerManager.html @@ -0,0 +1,4671 @@ + + + + + + ServerManager - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

ServerManager

+ + + + + + + +
+ +
+ +

+ core + + ServerManager +

+ +

This manager handles all communications between the experiment running in the participant's browser and the pavlovia.org server, in an asynchronous manner.

+

It is responsible for reading the configuration file of an experiment, for opening and closing a session, for listing and downloading resources, and for uploading results, logs, and audio recordings.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new ServerManager(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Event :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
RESOURCE + + +Symbol + + + +

Event type: resource event

DOWNLOADING_RESOURCES + + +Symbol + + + +

Event: resources have started to download

DOWNLOADING_RESOURCE + + +Symbol + + + +

Event: a specific resource download has started

RESOURCE_DOWNLOADED + + +Symbol + + + +

Event: a specific resource has been downloaded

DOWNLOAD_COMPLETED + + +Symbol + + + +

Event: resources have all downloaded

STATUS + + +Symbol + + + +

Event type: status event

+ + + + + + +
+

Server event

+

A server event is emitted by the manager to inform its listeners of either a change of status, or of a resource related event (e.g. download started, download is completed).

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) ResourceStatus :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ERROR + + +Symbol + + + +

There was an error during downloading, or the resource is in an unknown state.

REGISTERED + + +Symbol + + + +

The resource has been registered.

DOWNLOADING + + +Symbol + + + +

The resource is currently downloading.

DOWNLOADED + + +Symbol + + + +

The resource has been downloaded.

+ + + + + + +
+

Resource status

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) Status :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
READY + + +Symbol + + + +

The manager is ready.

BUSY + + +Symbol + + + +

The manager is busy, e.g. it is downloaded resources.

ERROR + + +Symbol + + + +

The manager has encountered an error, e.g. it was unable to download a resource.

+ + + + + + +
+

Server status

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(readonly) ALL_RESOURCES :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Used to indicate to the ServerManager that all resources must be registered (and +subsequently downloaded)

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(async, protected) _downloadResources(resources)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Download the specified resources.

+

Note: we use the preloadjs library.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
resources + + +Set + + + +

a set of names of previously registered resources

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _listResources()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

List the resources available to the experiment.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _queryServerAPI(method, path, data, contentTypeopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Query the pavlovia server API.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
method + + + + + + + + + +

the HTTP method, i.e. GET, PUT, POST, or DELETE

path + + + + + + + + + +

the resource path, without the server address

data + + + + + + + + + +

the data to be sent

contentType + + +string + + + + + + <optional>
+ + + + + +
+ + "JSON" + +

the content type, either JSON or FORM

+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupPreloadQueue()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the preload.js queue, and the associated callbacks.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) closeSession(isCompletedopt, syncopt) → {Promise.<ServerManager.CloseSessionPromise>|void}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Close the session for this experiment on the remote PsychoJS manager.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
isCompleted + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the experiment was completed

sync + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to communicate with the server in a synchronous manner

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.CloseSessionPromise> +| + +void + + +
+
+ + + + + + + + + + +

getConfiguration(configURL) → {Promise.<ServerManager.GetConfigurationPromise>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Read the configuration file for the experiment.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
configURL + + +string + + + +

the URL of the configuration file

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.GetConfigurationPromise> + + +
+
+ + + + + + + + + + +

getResource(name, errorIfNotDownloadedopt) → {Object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a resource.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +string + + + + + + + + + + + +

name of the requested resource

errorIfNotDownloaded + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to throw an exception if the +resource status is not DOWNLOADED

+ + + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+

exception if no resource with that name has previously been registered

+
+
+
+
+
+
+ Type +
+
+ +Object.<string, *> + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+

value of the resource, or undefined if the resource has been registered +but not downloaded yet.

+
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + +

getResourceStatus(names) → {module:core.ServerManager.ResourceStatus}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the status of a single resource or the reduced status of an array of resources.

+

If an array of resources is given, getResourceStatus returns a single, reduced status +that is the status furthest away from DOWNLOADED, with the status ordered as follow: +ERROR (furthest from DOWNLOADED), REGISTERED, DOWNLOADING, and DOWNLOADED

+

For example, given three resources: +

    +
  • if at least one of the resource status is ERROR, the reduced status is ERROR
  • +
  • if at least one of the resource status is DOWNLOADING, the reduced status is DOWNLOADING
  • +
  • if the status of all three resources is REGISTERED, the reduced status is REGISTERED
  • +
  • if the status of all three resources is DOWNLOADED, the reduced status is DOWNLOADED
  • +
+

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
names + + +string +| + +Array.<string> + + + +

names of the resources whose statuses are requested

+ + + + + + + + + + + + + + +
Throws:
+ + + +
+
+
+

if at least one of the names is not that of a previously +registered resource

+
+
+
+
+
+
+ Type +
+
+ +Object.<string, *> + + +
+
+
+
+
+ + + + + +
Returns:
+ + +
+

status of the resource if there is only one, or reduced status otherwise

+
+ + + +
+
+ Type +
+
+ +module:core.ServerManager.ResourceStatus + + +
+
+ + + + + + + + + + +

openSession() → {Promise.<ServerManager.OpenSessionPromise>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Open a session for this experiment on the remote PsychoJS manager.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.OpenSessionPromise> + + +
+
+ + + + + + + + + + +

(async) prepareResources(resourcesopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prepare resources for the experiment: register them with the server manager and possibly +start downloading them right away.

+
    +
  • For an experiment running locally: the root directory for the specified resources is that of index.html + unless they are prepended with a protocol, such as http:// or https://.
  • +
  • For an experiment running on the server: if no resources are specified, all files in the resources directory + of the experiment are downloaded, otherwise we only download the specified resources. All resources are assumed + local to index.html unless they are prepended with a protocol.
  • +
  • If resources is null, then we do not download any resources
  • +
+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
resources + + +String +| + +Array.<({name: string, path: string, download: boolean}|String|Symbol)> + + + + + + <optional>
+ + + + + +
+ + [] + +

the list of resources or a single resource

+ + + + + + + + + + + + + + + + + + + + + + + + +

resetStatus() → {ServerManager.Status.READY}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the resource manager status to ServerManager.Status.READY.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the new status

+
+ + + +
+
+ Type +
+
+ +ServerManager.Status.READY + + +
+
+ + + + + + + + + + +

setStatus()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the resource manager status.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) uploadAudioVideo(@param) → {Promise.<ServerManager.UploadDataPromise>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Synchronously or asynchronously upload audio data to the pavlovia server.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
@param + + +Object + + + + + + + + + + + +

options

options.mediaBlob + + +Blob + + + + + + + + + + + +

the audio or video blob to be uploaded

options.tag + + +string + + + + + + + + + + + +

additional tag

options.waitForCompletion + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to wait for completion +before returning

options.showDialog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to open a dialog box to inform the participant to wait for the data to be uploaded to the server

options.dialogMsg + + +string + + + + + + <optional>
+ + + + + +
+ + "Please wait a few moments while the data is uploading to the server" + +

default message informing the participant to wait for the data to be uploaded to the server

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.UploadDataPromise> + + +
+
+ + + + + + + + + + +

uploadData(key, value, syncopt) → {Promise.<ServerManager.UploadDataPromise>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Asynchronously upload experiment data to the pavlovia server.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
key + + +string + + + + + + + + + + + +

the data key (e.g. the name of .csv file)

value + + +string + + + + + + + + + + + +

the data value (e.g. a string containing the .csv header and records)

sync + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to communicate with the server in a synchronous manner

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.UploadDataPromise> + + +
+
+ + + + + + + + + + +

uploadLog(logs, compressedopt) → {Promise.<ServerManager.UploadDataPromise>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Asynchronously upload experiment logs to the pavlovia server.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
logs + + +string + + + + + + + + + + + +

the base64 encoded, compressed, formatted logs

compressed + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the logs are compressed

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response

+
+ + + +
+
+ Type +
+
+ +Promise.<ServerManager.UploadDataPromise> + + +
+
+ + + + + + + + + + +

waitForResources(resourcesopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Block the experiment until the specified resources have been downloaded.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
resources + + +Array.<{name: string, path: string}> + + + + + + <optional>
+ + + + + +
+ + [] + +

the list of resources

+ + + + + + + + + + + + + + + + + + + + + + + +

Type Definitions

+ + + +

CloseSessionPromise

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
origin + + +string + + + + + + + +

the calling method

context + + +string + + + + + + + +

the context

error + + +Object.<string, *> + + + + + + <optional>
+ + + +

an error message if we could not close the session (e.g. if it has not previously been opened)

+ + + + + + + + + + + + + + + +

GetConfigurationPromise

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
origin + + +string + + + + + + + +

the calling method

context + + +string + + + + + + + +

the context

config + + +Object.<string, *> + + + + + + <optional>
+ + + +

the configuration

error + + +Object.<string, *> + + + + + + <optional>
+ + + +

an error message if we could not read the configuration file

+ + + + + + + + + + + + + + + +

OpenSessionPromise

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
origin + + +string + + + + + + + +

the calling method

context + + +string + + + + + + + +

the context

token + + +string + + + + + + <optional>
+ + + +

the session token

error + + +Object.<string, *> + + + + + + <optional>
+ + + +

an error message if we could not open the session

+ + + + + + + + + + + + + + + +

UploadDataPromise

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
origin + + +string + + + + + + + +

the calling method

context + + +string + + + + + + + +

the context

error + + +Object.<string, *> + + + + + + <optional>
+ + + +

an error message if we could not upload the data

+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/ShapeStim.html b/docs/ShapeStim.html new file mode 100644 index 0000000..c85946e --- /dev/null +++ b/docs/ShapeStim.html @@ -0,0 +1,1780 @@ + + + + + + ShapeStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

ShapeStim

+ + + + + + + +
+ +
+ +

+ visual + + ShapeStim +

+ +

This class provides the basic functionality of shape stimuli.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new ShapeStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
    + +
  • ColorMixin
  • + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

lineWidth + + +number + + + + + + + + + + + +

the line width

lineColor + + +Color + + + + + + <optional>
+ + + + + +
+ + 'white' + +

the line color

fillColor + + +Color + + + + + + + + + + + +

the fill color

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

vertices + + +Array.<Array.<number>> + + + + + + <optional>
+ + + + + +
+ + [[-0.5, 0], [0, 0.5], [0.5, 0]] + +

the shape vertices

closeShape + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the shape is closed

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the shape

size + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the size

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

units + + +string + + + + + + + + + + + +

the units of the stimulus vertices, size and position

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth

interpolate + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the shape is interpolated

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) KnownShapes

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Known shapes.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getPixiPolygon() → {Object}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the PIXI polygon (in pixel units) corresponding to the vertices.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the PIXI polygon corresponding to this stimulus vertices.

+
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + +

(protected) _getVertices_px() → {Array.<Array.<number>>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the vertices in pixel units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the vertices (in pixel units)

+
+ + + +
+
+ Type +
+
+ +Array.<Array.<number>> + + +
+
+ + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

contains(object, units) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside the bounding box of the ShapeStim.

+

This is overridden in order to provide a finer inclusion test.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +string + + + +

the units

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the object is inside the bounding box of the ShapeStim

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

setVertices(vertices, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the vertices attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
vertices + + +Array.<Array.<number>> + + + + + + + + + + + +

the vertices

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-data.Shelf.html b/docs/Shelf.html similarity index 52% rename from docs/module-data.Shelf.html rename to docs/Shelf.html index 03d8cfd..88566a8 100644 --- a/docs/module-data.Shelf.html +++ b/docs/Shelf.html @@ -1,23 +1,47 @@ + - JSDoc: Class: Shelf - - - + Shelf - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Class: Shelf

+ + + + +
+ +

Shelf

+ @@ -28,33 +52,80 @@
-

- data.Shelf(options)

+

+ data + + Shelf +

+ +

Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the +server, and can be accessed and manipulated in a concurrent fashion.

-
+
+ - +

Constructor

+

new Shelf(options)

- -
-

Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the -server, and be accessed and manipulated in a concurrent fashion.

-

-
+
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + @@ -163,7 +234,7 @@ server, and be accessed and manipulated in a concurrent fashion.

- the PsychoJS instance +

the PsychoJS instance

@@ -197,12 +268,12 @@ server, and be accessed and manipulated in a concurrent fashion.

- false + false - whether to log +

whether to log

@@ -221,69 +292,24 @@ server, and be accessed and manipulated in a concurrent fashion.

-
+ + + + + + + + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -

Extends

@@ -299,10 +325,10 @@ server, and be accessed and manipulated in a concurrent fashion.

- + - + @@ -311,26 +337,7 @@ server, and be accessed and manipulated in a concurrent fashion.

-

(static) MAX_KEY_LENGTH :number

- - - - -
- Maximum number of components in a key -
- - - -
Type:
-
    -
  • - -number - - -
  • -
+

(static, readonly) Status :Symbol

@@ -339,33 +346,9 @@ server, and be accessed and manipulated in a concurrent fashion.

- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -374,22 +357,136 @@ server, and be accessed and manipulated in a concurrent fashion.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
Properties:
+ + + + + + + + + + + + + + + + + + + + -

(static, readonly) Type :Symbol

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
READY + + +Symbol + + + +

The shelf is ready.

BUSY + + +Symbol + + + +

The shelf is busy, e.g. storing or retrieving values.

ERROR + + +Symbol + + + +

The shelf has encountered an error.

-
- Shelf record types. + + +
+

Shelf status

@@ -408,6 +505,57 @@ server, and be accessed and manipulated in a concurrent fashion.

+ + + +

(static, readonly) Type :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
Properties:
@@ -552,60 +700,10 @@ server, and be accessed and manipulated in a concurrent fashion.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - -

(readonly) Status :Symbol

- - - - -
- Shelf status +
+

Shelf record types.

@@ -624,36 +722,31 @@ server, and be accessed and manipulated in a concurrent fashion.

+ + + + + +

Methods

+ + + + + + +

_checkAvailability(methodNameopt)

+ + + + + +
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -662,35 +755,38 @@ server, and be accessed and manipulated in a concurrent fashion.

+ + + + + + + + + + + + + + + + + + + + + + + +
- - - - - -

Methods

- - - - - - - -

_checkAvailability(methodNameopt)

- - - - - - -
- Check whether it is possible to run a given shelf command. - +
+

Check whether it is possible to run a given shelf command.

Since all Shelf methods call _checkAvailability, we also use it as a means to throttle those calls.

@@ -702,6 +798,8 @@ server, and be accessed and manipulated in a concurrent fashion.

+ +
Parameters:
@@ -758,12 +856,12 @@ server, and be accessed and manipulated in a concurrent fashion.

- "" + "" - name of the method requiring a check +

name of the method requiring a check

@@ -775,50 +873,6 @@ server, and be accessed and manipulated in a concurrent fashion.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -833,13 +887,13 @@ server, and be accessed and manipulated in a concurrent fashion.

-
- exception if it is not possible to run the given shelf command +
+

exception if it is not possible to run the given shelf command

-
+
Type
@@ -861,23 +915,64 @@ server, and be accessed and manipulated in a concurrent fashion.

- - -

_checkKey(key)

- -
- Check the validity of the key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check the validity of the key.

@@ -888,6 +983,8 @@ server, and be accessed and manipulated in a concurrent fashion.

+ +
Parameters:
@@ -929,7 +1026,7 @@ server, and be accessed and manipulated in a concurrent fashion.

- key whose validity is to be checked +

key whose validity is to be checked

@@ -941,50 +1038,6 @@ server, and be accessed and manipulated in a concurrent fashion.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -999,13 +1052,13 @@ server, and be accessed and manipulated in a concurrent fashion.

-
- exception if the key is invalid +
+

exception if the key is invalid

-
+
Type
@@ -1027,24 +1080,64 @@ server, and be accessed and manipulated in a concurrent fashion.

- - - -

(protected) _getValue(key, type, optionsopt) → {Promise.<any>}

- +

(async) _getValue(key, type, optionsopt) → {Promise.<any>}

-
- Get the value associated with the given key. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value associated with the given key.

This is a generic method, typically called from the Shelf helper methods, e.g. getBinaryValue.

@@ -1056,6 +1149,8 @@ server, and be accessed and manipulated in a concurrent fashion.

+ +
Parameters:
@@ -1107,7 +1202,7 @@ server, and be accessed and manipulated in a concurrent fashion.

- key as an array of key components +

key as an array of key components

@@ -1120,7 +1215,7 @@ server, and be accessed and manipulated in a concurrent fashion.

-Shelf.Type +Shelf.Type @@ -1138,7 +1233,7 @@ server, and be accessed and manipulated in a concurrent fashion.

- the type of the record associated with the given key +

the type of the record associated with the given key

@@ -1171,8 +1266,8 @@ server, and be accessed and manipulated in a concurrent fashion.

- the options, e.g. the default value returned if no record with the -given key exists on the shelf +

the options, e.g. the default value returned if no record with the +given key exists on the shelf

@@ -1184,50 +1279,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1242,14 +1293,14 @@ given key exists on the shelf
-
- exception if there is a record associated with the given key but it is not of - the given type +
+

exception if there is a record associated with the given key but it is not of +the given type

-
+
Type
@@ -1272,12 +1323,12 @@ given key exists on the shelf
- the value +

the value

-
+
Type
@@ -1293,24 +1344,64 @@ given key exists on the shelf - - - -

(protected) _updateValue(key, type, update) → {Promise.<any>}

- +

(async) _updateValue(key, type, update) → {Promise.<any>}

-
- Update the value associated with the given key. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the value associated with the given key.

This is a generic method, typically called from the Shelf helper methods, e.g. setBinaryValue.

@@ -1322,6 +1413,8 @@ given key exists on the shelf + +
Parameters:
@@ -1363,7 +1456,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -1376,7 +1469,7 @@ given key exists on the shelf -Shelf.Type +Shelf.Type @@ -1386,7 +1479,7 @@ given key exists on the shelf - the type of the record associated with the given key +

the type of the record associated with the given key

@@ -1409,7 +1502,7 @@ given key exists on the shelf - the desired update +

the desired update

@@ -1421,50 +1514,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1479,14 +1528,14 @@ given key exists on the shelf
-
- exception if there is no record associated with the given key or if there is one - but it is not of the given type +
+

exception if there is no record associated with the given key or if there is one +but it is not of the given type

-
+
Type
@@ -1509,12 +1558,12 @@ given key exists on the shelf
- the updated value +

the updated value

-
+
Type
@@ -1530,23 +1579,64 @@ given key exists on the shelf - - -

addIntegerValue(options) → {Promise.<number>}

- -
- Add a delta to the value of a record of type INTEGER associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a delta to the value of a record of type INTEGER associated with the given key.

@@ -1557,6 +1647,8 @@ given key exists on the shelf + +
Parameters:
@@ -1640,7 +1732,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -1663,7 +1755,7 @@ given key exists on the shelf - the delta, positive or negative, to add to the value +

the delta, positive or negative, to add to the value

@@ -1682,50 +1774,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1740,14 +1788,14 @@ given key exists on the shelf
-
- exception if delta is not an integer, or if there is no record with the given - key, or if there is a record but it is locked or it is not of type INTEGER +
+

exception if delta is not an integer, or if there is no record with the given +key, or if there is a record but it is locked or it is not of type INTEGER

-
+
Type
@@ -1770,12 +1818,12 @@ given key exists on the shelf
- the new value +

the new value

-
+
Type
@@ -1791,23 +1839,64 @@ given key exists on the shelf - - -

appendListValue(options) → {Promise.<Array.<*>>}

- -
- Append an element, or a list of elements, to the value of a record of type LIST associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Append an element, or a list of elements, to the value of a record of type LIST associated with the given key.

@@ -1818,6 +1907,8 @@ given key exists on the shelf + +
Parameters:
@@ -1901,7 +1992,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -1924,7 +2015,7 @@ given key exists on the shelf - the element or list of elements to be appended +

the element or list of elements to be appended

@@ -1943,50 +2034,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2001,14 +2048,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type LIST +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type LIST

-
+
Type
@@ -2031,12 +2078,12 @@ given key exists on the shelf
- the new value +

the new value

-
+
Type
@@ -2052,23 +2099,64 @@ given key exists on the shelf - - -

clearListValue(options) → {Promise.<Array.<*>>}

- -
- Empty the value of a record of type LIST associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Empty the value of a record of type LIST associated with the given key.

@@ -2079,6 +2167,8 @@ given key exists on the shelf + +
Parameters:
@@ -2162,7 +2252,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -2181,50 +2271,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2239,14 +2285,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type LIST +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type LIST

-
+
Type
@@ -2269,12 +2315,12 @@ given key exists on the shelf
- the new, empty value, i.e. [] +

the new, empty value, i.e. []

-
+
Type
@@ -2290,23 +2336,64 @@ given key exists on the shelf - - - -

counterBalanceSelect(key, groups, groupSizes) → {Promise.<any>}

- +

(async) counterBalanceSelect(options) → {Promise.<{string, boolean}>}

-
- Get the name of a group, using a counterbalanced design. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the name of a group, using a counterbalanced design.

@@ -2317,6 +2404,8 @@ given key exists on the shelf + +
Parameters:
@@ -2333,6 +2422,48 @@ given key exists on the shelf + Description + + + + + + + + + options + + + + + +Object + + + + + + + + + + +
Properties
+ + + + + + + + + + + + + + + @@ -2358,7 +2489,7 @@ given key exists on the shelf - + @@ -2381,7 +2512,7 @@ given key exists on the shelf - + @@ -2404,57 +2535,20 @@ given key exists on the shelf - +
NameTypeDescription
key as an array of key components

key as an array of key components

the names of the groups

the names of the groups

the size of the groups

the size of the groups

- - - - - -
+ + + + - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
@@ -2473,15 +2567,20 @@ given key exists on the shelf
Returns:
+
+

an object with the name of the selected group and whether all groups +have been depleted

+
-
+ +
Type
-Promise.<any> +Promise.<{string, boolean}>
@@ -2491,23 +2590,64 @@ given key exists on the shelf - - -

flipBooleanValue(options) → {Promise.<boolean>}

- -
- Flip the value of a record of type BOOLEAN associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Flip the value of a record of type BOOLEAN associated with the given key.

@@ -2518,6 +2658,8 @@ given key exists on the shelf + +
Parameters:
@@ -2601,7 +2743,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -2620,50 +2762,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2678,14 +2776,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, or - if there is a record but it is not of type BOOLEAN +
+

exception if there is no record with the given key, or +if there is a record but it is not of type BOOLEAN

-
+
Type
@@ -2708,12 +2806,12 @@ given key exists on the shelf
- the new, flipped, value +

the new, flipped, value

-
+
Type
@@ -2729,23 +2827,64 @@ given key exists on the shelf - - -

getBooleanValue(options) → {Promise.<boolean>}

- -
- Get the value of a record of type BOOLEAN associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a record of type BOOLEAN associated with the given key.

@@ -2756,6 +2895,8 @@ given key exists on the shelf + +
Parameters:
@@ -2839,7 +2980,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -2862,8 +3003,8 @@ given key exists on the shelf - the default value returned if no record with the given key exists - on the shelf +

the default value returned if no record with the given key exists +on the shelf

@@ -2882,50 +3023,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2940,14 +3037,14 @@ given key exists on the shelf
-
- exception if there is a record associated with the given key - but it is not of type BOOLEAN +
+

exception if there is a record associated with the given key +but it is not of type BOOLEAN

-
+
Type
@@ -2970,12 +3067,12 @@ given key exists on the shelf
- the value associated with the key +

the value associated with the key

-
+
Type
@@ -2991,23 +3088,64 @@ given key exists on the shelf - - - -

getDictionaryFieldNames(options) → {Promise.<Array.<string>>}

- +

(async) getDictionaryFieldNames(options) → {Promise.<Array.<string>>}

-
- Get the names of the fields in the dictionary record associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the names of the fields in the dictionary record associated with the given key.

@@ -3018,6 +3156,8 @@ given key exists on the shelf + +
Parameters:
@@ -3101,7 +3241,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -3120,50 +3260,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3178,14 +3274,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type DICTIONARY +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type DICTIONARY

-
+
Type
@@ -3208,12 +3304,12 @@ given key exists on the shelf
- the list of field names +

the list of field names

-
+
Type
@@ -3229,23 +3325,64 @@ given key exists on the shelf - - - -

getDictionaryFieldValue(options) → {Promise.<*>}

- +

(async) getDictionaryFieldValue(options) → {Promise.<*>}

-
- Get the value of a given field in the dictionary record associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a given field in the dictionary record associated with the given key.

@@ -3256,6 +3393,8 @@ given key exists on the shelf + +
Parameters:
@@ -3339,7 +3478,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -3362,7 +3501,7 @@ given key exists on the shelf - the name of the field +

the name of the field

@@ -3385,8 +3524,8 @@ given key exists on the shelf - the default value returned if no record with the given key exists on - the shelf, or if is a record of type DICTIONARY with the given key but it has no such field +

the default value returned if no record with the given key exists on +the shelf, or if is a record of type DICTIONARY with the given key but it has no such field

@@ -3405,50 +3544,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3463,14 +3558,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, - or if there is a record but it is locked or it is not of type DICTIONARY +
+

exception if there is no record with the given key, +or if there is a record but it is locked or it is not of type DICTIONARY

-
+
Type
@@ -3493,12 +3588,12 @@ given key exists on the shelf
- the value of that field +

the value of that field

-
+
Type
@@ -3514,23 +3609,64 @@ given key exists on the shelf - - -

getDictionaryValue(options) → {Promise.<Object.<string, *>>}

- -
- Get the value of a record of type DICTIONARY associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a record of type DICTIONARY associated with the given key.

@@ -3541,6 +3677,8 @@ given key exists on the shelf + +
Parameters:
@@ -3624,7 +3762,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -3647,8 +3785,8 @@ given key exists on the shelf - the default value returned if no record with the given key - exists on the shelf +

the default value returned if no record with the given key +exists on the shelf

@@ -3667,50 +3805,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3725,14 +3819,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, - or if there is a record but it is locked or it is not of type DICTIONARY +
+

exception if there is no record with the given key, +or if there is a record but it is locked or it is not of type DICTIONARY

-
+
Type
@@ -3755,12 +3849,12 @@ given key exists on the shelf
- the value associated with the key +

the value associated with the key

-
+
Type
@@ -3776,23 +3870,64 @@ given key exists on the shelf - - -

getIntegerValue(options) → {Promise.<number>}

- -
- Get the value of a record of type INTEGER associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a record of type INTEGER associated with the given key.

@@ -3803,6 +3938,8 @@ given key exists on the shelf + +
Parameters:
@@ -3886,7 +4023,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -3909,8 +4046,8 @@ given key exists on the shelf - the default value returned if no record with the given key - exists on the shelf +

the default value returned if no record with the given key +exists on the shelf

@@ -3929,50 +4066,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3987,14 +4080,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, - or if there is a record but it is locked or it is not of type BOOLEAN +
+

exception if there is no record with the given key, +or if there is a record but it is locked or it is not of type BOOLEAN

-
+
Type
@@ -4017,12 +4110,12 @@ given key exists on the shelf
- the value associated with the key +

the value associated with the key

-
+
Type
@@ -4038,23 +4131,64 @@ given key exists on the shelf - - -

getListValue(options) → {Promise.<Array.<*>>}

- -
- Get the value of a record of type LIST associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a record of type LIST associated with the given key.

@@ -4065,6 +4199,8 @@ given key exists on the shelf + +
Parameters:
@@ -4148,7 +4284,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -4171,8 +4307,8 @@ given key exists on the shelf - the default value returned if no record with the given key exists on - the shelf +

the default value returned if no record with the given key exists on +the shelf

@@ -4191,50 +4327,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -4249,14 +4341,14 @@ given key exists on the shelf
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type LIST +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type LIST

-
+
Type
@@ -4279,12 +4371,12 @@ given key exists on the shelf
- the value associated with the key +

the value associated with the key

-
+
Type
@@ -4300,23 +4392,64 @@ given key exists on the shelf - - -

getTextValue(options) → {Promise.<string>}

- -
- Get the value of a record of type TEXT associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the value of a record of type TEXT associated with the given key.

@@ -4327,6 +4460,8 @@ given key exists on the shelf + +
Parameters:
@@ -4410,7 +4545,7 @@ given key exists on the shelf - key as an array of key components +

key as an array of key components

@@ -4433,8 +4568,8 @@ given key exists on the shelf - the default value returned if no record with the given key exists on - the shelf +

the default value returned if no record with the given key exists on +the shelf

@@ -4453,50 +4588,6 @@ given key exists on the shelf -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -4511,14 +4602,14 @@ given key exists on the shelf
-
- exception if there is a record associated with the given key but it is - not of type TEXT +
+

exception if there is a record associated with the given key but it is +not of type TEXT

-
+
Type
@@ -4541,12 +4632,12 @@ given key exists on the shelf
- the value associated with the key +

the value associated with the key

-
+
Type
@@ -4562,24 +4653,65 @@ given key exists on the shelf - - -

incrementComponent(key, increment, callback) → {function}

- -
- Schedulable component that will block the experiment until the counter associated with the given key -has been incremented by the given amount. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Schedulable component that will block the experiment until the counter associated with the given key +has been incremented by the given amount.

@@ -4590,6 +4722,15 @@ has been incremented by the given amount. +
Example
+ +
const flowScheduler = new Scheduler(psychoJS);
+var experimentCounter = '<>';
+flowScheduler.add(psychoJS.shelf.incrementComponent(['counter'], 1, (value) => experimentCounter = value));
+ + + +
Parameters:
@@ -4605,6 +4746,8 @@ has been incremented by the given amount. + Default + Description @@ -4625,6 +4768,10 @@ has been incremented by the given amount. + + + + @@ -4643,6 +4790,12 @@ has been incremented by the given amount. + + + 1 + + + @@ -4661,6 +4814,10 @@ has been incremented by the given amount. + + + + @@ -4674,50 +4831,6 @@ has been incremented by the given amount. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -4732,12 +4845,12 @@ has been incremented by the given amount.
- a component that can be scheduled +

a component that can be scheduled

-
+
Type
@@ -4753,31 +4866,65 @@ has been incremented by the given amount. - -
Example
- -
const flowScheduler = new Scheduler(psychoJS);
-var experimentCounter = '<>';
-flowScheduler.add(psychoJS.shelf.incrementComponent(['counter'], 1, (value) => experimentCounter = value));
- - - -

popListValue(options) → {Promise.<*>}

- -
- Pop an element, at the given index, from the value of a record of type LIST associated -with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Pop an element, at the given index, from the value of a record of type LIST associated +with the given key.

@@ -4788,6 +4935,8 @@ with the given key. + +
Parameters:
@@ -4887,7 +5036,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -4921,12 +5070,12 @@ with the given key. - -1 + -1 - the index of the element to be popped +

the index of the element to be popped

@@ -4945,50 +5094,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -5003,14 +5108,14 @@ with the given key.
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type LIST +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type LIST

-
+
Type
@@ -5033,12 +5138,12 @@ with the given key.
- the popped element +

the popped element

-
+
Type
@@ -5054,23 +5159,64 @@ with the given key. - - -

setBooleanValue(options) → {Promise.<boolean>}

- -
- Set the value of a record of type BOOLEAN associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of a record of type BOOLEAN associated with the given key.

@@ -5081,6 +5227,8 @@ with the given key. + +
Parameters:
@@ -5164,7 +5312,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -5187,7 +5335,7 @@ with the given key. - the new value +

the new value

@@ -5206,50 +5354,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -5264,14 +5368,14 @@ with the given key.
-
- exception if value is not a boolean, or if there is no record with the given - key, or if there is a record but it is locked or it is not of type BOOLEAN +
+

exception if value is not a boolean, or if there is no record with the given +key, or if there is a record but it is locked or it is not of type BOOLEAN

-
+
Type
@@ -5294,12 +5398,12 @@ with the given key.
- the new value +

the new value

-
+
Type
@@ -5315,23 +5419,64 @@ with the given key. - - - -

setDictionaryFieldValue(options) → {Promise.<Object.<string, *>>}

- +

(async) setDictionaryFieldValue(options) → {Promise.<Object.<string, *>>}

-
- Set a field in the dictionary record associated to the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set a field in the dictionary record associated to the given key.

@@ -5342,6 +5487,8 @@ with the given key. + +
Parameters:
@@ -5425,7 +5572,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -5448,7 +5595,7 @@ with the given key. - the name of the field +

the name of the field

@@ -5471,7 +5618,7 @@ with the given key. - the value of the field +

the value of the field

@@ -5490,50 +5637,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -5548,14 +5651,14 @@ with the given key.
-
- exception if there is no record with the given key, - or if there is a record but it is locked or it is not of type DICTIONARY +
+

exception if there is no record with the given key, +or if there is a record but it is locked or it is not of type DICTIONARY

-
+
Type
@@ -5578,12 +5681,12 @@ with the given key.
- the updated dictionary +

the updated dictionary

-
+
Type
@@ -5599,23 +5702,64 @@ with the given key. - - -

setDictionaryValue(options) → {Promise.<Object.<string, *>>}

- -
- Set the value of a record of type DICTIONARY associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of a record of type DICTIONARY associated with the given key.

@@ -5626,6 +5770,8 @@ with the given key. + +
Parameters:
@@ -5709,7 +5855,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -5732,7 +5878,7 @@ with the given key. - the new value +

the new value

@@ -5751,50 +5897,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -5809,14 +5911,14 @@ with the given key.
-
- exception if value is not an object, or or if there is no record - with the given key, or if there is a record but it is locked or it is not of type DICTIONARY +
+

exception if value is not an object, or or if there is no record +with the given key, or if there is a record but it is locked or it is not of type DICTIONARY

-
+
Type
@@ -5839,12 +5941,12 @@ with the given key.
- the new value +

the new value

-
+
Type
@@ -5860,23 +5962,64 @@ with the given key. - - -

setIntegerValue(options) → {Promise.<number>}

- -
- Set the value of a record of type INTEGER associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of a record of type INTEGER associated with the given key.

@@ -5887,6 +6030,8 @@ with the given key. + +
Parameters:
@@ -5970,7 +6115,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -5993,7 +6138,7 @@ with the given key. - the new value +

the new value

@@ -6012,50 +6157,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -6070,14 +6171,14 @@ with the given key.
-
- exception if value is not an integer, or or if there is no record - with the given key, or if there is a record but it is locked or it is not of type INTEGER +
+

exception if value is not an integer, or or if there is no record +with the given key, or if there is a record but it is locked or it is not of type INTEGER

-
+
Type
@@ -6100,12 +6201,12 @@ with the given key.
- the new value +

the new value

-
+
Type
@@ -6121,23 +6222,64 @@ with the given key. - - -

setListValue(options) → {Promise.<Array.<*>>}

- -
- Set the value of a record of type LIST associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of a record of type LIST associated with the given key.

@@ -6148,6 +6290,8 @@ with the given key. + +
Parameters:
@@ -6231,7 +6375,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -6254,7 +6398,7 @@ with the given key. - the new value +

the new value

@@ -6273,50 +6417,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -6331,14 +6431,14 @@ with the given key.
-
- exception if value is not an array or if there is no record with the given key, - or if there is a record but it is locked or it is not of type LIST +
+

exception if value is not an array or if there is no record with the given key, +or if there is a record but it is locked or it is not of type LIST

-
+
Type
@@ -6361,12 +6461,12 @@ with the given key.
- the new value +

the new value

-
+
Type
@@ -6382,23 +6482,64 @@ with the given key. - - -

setTextValue(options) → {Promise.<string>}

- -
- Set the value of a record of type TEXT associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of a record of type TEXT associated with the given key.

@@ -6409,6 +6550,8 @@ with the given key. + +
Parameters:
@@ -6492,7 +6635,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -6515,7 +6658,7 @@ with the given key. - the new value +

the new value

@@ -6534,50 +6677,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -6592,14 +6691,14 @@ with the given key.
-
- exception if value is not a string, or if there is a record associated - with the given key but it is not of type TEXT +
+

exception if value is not a string, or if there is a record associated +with the given key but it is not of type TEXT

-
+
Type
@@ -6622,12 +6721,12 @@ with the given key.
- the new value +

the new value

-
+
Type
@@ -6643,23 +6742,64 @@ with the given key. - - -

shuffleListValue(options) → {Promise.<Array.<*>>}

- -
- Shuffle the elements of the value of a record of type LIST associated with the given key. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Shuffle the elements of the value of a record of type LIST associated with the given key.

@@ -6670,6 +6810,8 @@ with the given key. + +
Parameters:
@@ -6753,7 +6895,7 @@ with the given key. - key as an array of key components +

key as an array of key components

@@ -6772,50 +6914,6 @@ with the given key. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -6830,14 +6928,14 @@ with the given key.
-
- exception if there is no record with the given key, or if there is a record - but it is locked or it is not of type LIST +
+

exception if there is no record with the given key, or if there is a record +but it is locked or it is not of type LIST

-
+
Type
@@ -6860,12 +6958,12 @@ with the given key.
- the new, shuffled value +

the new, shuffled value

-
+
Type
@@ -6881,8 +6979,6 @@ with the given key. - - @@ -6896,19 +6992,23 @@ with the given key. + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/Slider.html b/docs/Slider.html new file mode 100644 index 0000000..781b55f --- /dev/null +++ b/docs/Slider.html @@ -0,0 +1,7169 @@ + + + + + + Slider - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Slider

+ + + + + + + +
+ +
+ +

+ visual + + Slider +

+ +

Slider stimulus.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Slider(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
+ + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • check that parameters are valid, e.g. ticks are an array of numbers, etc.
  • + +
  • readOnly
  • + +
  • complete setters, for instance setTicks should change this._isCategorical
  • + +
  • flesh out the skin approach
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the slider

size + + +Array.<number> + + + + + + + + + + + +

the size of the slider, e.g. [1, 0.1] for an horizontal slider

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

units + + +string + + + + + + <optional>
+ + + + + +
+ + 'height' + +

the units of the Slider position, and font size

color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('LightGray') + +

the color of the slider

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast of the slider

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity of the slider

style + + +string + + + + + + <optional>
+ + + + + +
+ + [Slider.Style.RATING] + +

the slider style

ticks + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [1,2,3,4,5] + +

the array of ticks

labels + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [] + +

the array of labels

granularity + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the granularity

flip + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip the position of the marker, ticks, +and labels with respect to the central bar

readOnly + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the slider is read only

font + + +string + + + + + + <optional>
+ + + + + +
+ + 'Arial' + +

the text font

bold + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the font of the labels is bold

italic + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the font of the labels is italic

fontSize + + +number + + + + + + <optional>
+ + + + + +
+ +

the font size of the labels (in pixels), the default fontSize depends on the +Slider's units: 14 for 'pix', 0.03 otherwise

compact + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the slider is compact, i.e. whether all graphical +elements (e.g. labels) fit within its size

clipMask + + +PIXI.Graphics + + + + + + + + + + + +

the clip mask

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every +frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

dependentStims + + +Array.<core.MinimalStim> + + + + + + <optional>
+ + + + + +
+ + [] + +

the list of dependent stimuli, +which must be updated when this Slider is updated, e.g. a Form.

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

(static, readonly) Shape :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
DISC + + +Symbol + + + +
TRIANGLE + + +Symbol + + + +
LINE + + +Symbol + + + +
BOX + + +Symbol + + + +
+ + + + + + +
+

Shape of the marker and of the ticks.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

(static, readonly) Skin :any

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
MARKER_SIZE + + +any + + + +
STANDARD + + +any + + + +
WHITE_ON_BLACK + + +any + + + +
+ + + + + + +
+

Skin.

+
+ + + +
Type:
+
    +
  • + +any + + +
  • +
+ + + + + + + + +

(static, readonly) Style :Symbol

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
RATING + + +Symbol + + + +
TRIANGLE_MARKER + + +Symbol + + + +
SLIDER + + +Symbol + + + +
WHITE_ON_BLACK + + +Symbol + + + +
LABELS_45 + + +Symbol + + + +
RADIO + + +Symbol + + + +
+ + + + + + +
+

Styles.

+
+ + + +
Type:
+
    +
  • + +Symbol + + +
  • +
+ + + + + + + + +

borderColor

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Let borderColor alias lineColor to parallel PsychoPy

+
+ + + + + + + + + + +

fillColor

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Let fillColor alias markerColor to parallel PsychoPy

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _addEventListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add event listeners.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getBoundingBox_px() → {PIXI.Rectangle}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the bounding box in pixel coordinates

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the bounding box, in pixel coordinates

+
+ + + +
+
+ Type +
+
+ +PIXI.Rectangle + + +
+
+ + + + + + + + + + +

(protected) _getPosition_px() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the position of the slider, taking the compactness into account.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the position of the slider, in pixels
  • +
+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _getTextStyle()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the PIXI Text Style applied to the PIXI.Text labels.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _granularise(rating) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Calculate the rating once granularity has been taken into account.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
rating + + +number + + + +

the input rating

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the new rating with granularity applied

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected) _handlePointerDown()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Handle pointerdown event.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _handlePointerMove()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Handle pointermove event.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _handlePointerUp()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Handle pointerup event.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _isHorizontal() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether the slider is horizontal.

+

The slider is horizontal is its x-axis size is larger than its y-axis size.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the slider is horizontal

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

(protected) _onChange(withPixiopt, withBoundingBoxopt) → {function}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Generate a callback that prepares updates to the stimulus. +This is typically called in the constructor of a stimulus, when attributes are added +with _addAttribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
withPixi + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the PIXI representation must +also be updated

withBoundingBox + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to immediately estimate +the bounding box

+ + + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +function + + +
+
+ + + + + + + + + + +

(protected) _posToRating(pos_px) → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert a [x,y] position, in pixel units, relative to the slider, into a rating.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pos_px + + +Array.<number> + + + +

the [x,y] position, in pixel units, relative to the slider.

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the corresponding rating.

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected) _ratingToPos(ratings) → {Array.<Array.<number>>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert an array of ratings into an array of [x,y] positions (in Slider units, with 0 at the center of the Slider)

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ratings + + +Array.<number> + + + +

the array of ratings

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the positions corresponding to the ratings (in Slider units, +with 0 at the center of the Slider)

+
+ + + +
+
+ Type +
+
+ +Array.<Array.<number>> + + +
+
+ + + + + + + + + + +

(protected) _removeEventListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Remove event listeners.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _sanitizeAttributes()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Sanitize the slider attributes: check for attribute conflicts, missing values, etc.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupBar()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the central bar.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupLabels()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the labels.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupMarker()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the marker, and the associated mouse events.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupSlider()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the PIXI components of the slider (bar, ticks, labels, marker, etc.).

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupStyle()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Apply a particular style to the slider.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupTicks()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup the ticks.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

contains(object, units) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether an object is inside the bounding box of the stimulus.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
object + + +Object + + + +

the object

units + + +string + + + +

the units

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the object is inside the bounding box of the stimulus

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

draw()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Draw this stimulus on the next frame draw.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getRating() → {number|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current value of the rating.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the rating or undefined if there is none

+
+ + + +
+
+ Type +
+
+ +number +| + +undefined + + +
+
+ + + + + + + + + + +

getRT() → {number|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the response time of the most recent change to the rating.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the response time (in second) or undefined if there is none

+
+ + + +
+
+ Type +
+
+ +number +| + +undefined + + +
+
+ + + + + + + + + + +

hide()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Hide this stimulus on the next frame draw.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

isMarkerDragging() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Query whether or not the marker is currently being dragged.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the marker is being dragged

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

recordRating(rating, responseTimeopt, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the current rating.

+

Setting the rating does also change the visible position of the marker.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
rating + + +number + + + + + + + + + + + +

the rating

responseTime + + +number + + + + + + <optional>
+ + + + + +
+ +

the reaction time

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

refresh()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Force a refresh of the stimulus.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

release(logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Release the PIXI representation, if there is one.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

reset()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Reset the slider.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setAutoDraw(autoDraw, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the autoDraw attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
autoDraw + + +boolean + + + + + + + + + + + +

the new value

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setDepth(depth, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the depth attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
depth + + +Array.<number> + + + + + + + + + + + + 0 + +

order in which stimuli is rendered, kind of css's z-index with a negative sign.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setMarkerPos(displayedRating, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the markerPos attribute.

+

Setting markerPos changes the visible position of the marker to the specified rating +but does not change the actual rating returned by the slider.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
displayedRating + + +number + + + + + + + + + + + +

the displayed rating

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setOri(ori, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the orientation attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
ori + + +number + + + + + + + + + + + + 0 + +

the orientation in degree with 0 as the vertical position, positive values rotate clockwise.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setPos(pos, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the position attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
pos + + +Array.<number> + + + + + + + + + + + +

position of the center of the stimulus, in stimulus units

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setRating(rating, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the rating attribute.

+

Setting the rating does not change the visible position of the marker.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
rating + + +number + + + + + + + + + + + +

the rating

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setReadOnly(readOnlyopt, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the readOnly attribute.

+

Read-only sliders are half-opaque and do not provide responses.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
readOnly + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the slider is read-only

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setSize(size, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the size attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
size + + +undefined +| + +null +| + +number +| + +Array.<number> + + + + + + + + + + + +

the stimulus size

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/SoundPlayer.html b/docs/SoundPlayer.html new file mode 100644 index 0000000..716df83 --- /dev/null +++ b/docs/SoundPlayer.html @@ -0,0 +1,1079 @@ + + + + + + SoundPlayer - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

SoundPlayer

+ + + + + + + +
+ +
+ +

+ sound + + SoundPlayer +

+ +

SoundPlayer is an interface for the sound players, who are responsible for actually playing the sounds, i.e. the tracks or the tones.

+ + +
+ +
+ +
+ + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(abstract, static) accept(sound) → {Object|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether this player can play the given sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sound + + +module:sound.Sound + + + +

the sound

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

an instance of the SoundPlayer that can play the sound, or undefined if none could be found

+
+ + + +
+
+ Type +
+
+ +Object +| + +undefined + + +
+
+ + + + + + + + + + +

(abstract) getDuration()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the sound, in seconds.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) play(loopsopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
loops + + +number + + + + + + <optional>
+ + + + + +

how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) setDuration()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the duration of the sound, in seconds.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) setLoops(loops)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the number of loops.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loops + + +number + + + +

how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) setVolume(volume, muteopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the volume of the tone.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
volume + + +Integer + + + + + + + + + + + +

the volume of the tone

mute + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to mute the tone

+ + + + + + + + + + + + + + + + + + + + + + + + +

(abstract) stop()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the sound immediately.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/SpeechRecognition.html b/docs/SpeechRecognition.html new file mode 100644 index 0000000..8bd9a3a --- /dev/null +++ b/docs/SpeechRecognition.html @@ -0,0 +1,1436 @@ + + + + + + SpeechRecognition - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

SpeechRecognition

+ + + + + + + +
+ +
+ +

+ sound + + SpeechRecognition +

+ +

This manager handles the live transcription of speech into text.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new SpeechRecognition(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • deal with alternatives, interim results, and recognition errors
  • +
+
+ +
+ + + + + +
+

This manager handles the live transcription of speech into text.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

name + + +String + + + + + + + + + + + +

the name used when logging messages

bufferSize + + +number + + + + + + <optional>
+ + + + + +
+ + 10000 + +

the maximum size of the circular transcript buffer

continuous + + +Array.<String> + + + + + + <optional>
+ + + + + +
+ + true + +

whether to continuously recognise

lang + + +Array.<String> + + + + + + <optional>
+ + + + + +
+ + 'en-US' + +

the spoken language

interimResults + + +Array.<String> + + + + + + <optional>
+ + + + + +
+ + false + +

whether to make interim results available

maxAlternatives + + +Array.<String> + + + + + + <optional>
+ + + + + +
+ + 1 + +

the maximum number of recognition alternatives

tokens + + +Array.<String> + + + + + + <optional>
+ + + + + +
+ + [] + +

the tokens to be recognised. This is experimental technology, not available in all browser.

clock + + +Clock + + + + + + <optional>
+ + + + + +
+ +

an optional clock

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _onChange()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback for changes to the recognition settings.

+

Changes to the recognition settings require the speech recognition process +to be stopped and be re-started.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _prepareRecognition()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prepare the speech recognition process.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

clearTranscripts()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clear all transcripts and resets the circular buffers.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getTranscripts(options) → {Array.<Transcript>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the list of transcripts still in the buffer, i.e. those that have not been +previously cleared by calls to getTranscripts with clear = true.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
transcriptList + + +Array.<string> + + + + + + <optional>
+ + + + + +
+ + [] + +

the list of transcripts texts to consider. If transcriptList is empty, we consider all transcripts.

clear + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to keep in the buffer the transcripts for a subsequent call to getTranscripts. If a keyList has been given and clear = true, we only remove from the buffer those keys in keyList

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the list of transcripts still in the buffer

+
+ + + +
+
+ Type +
+
+ +Array.<Transcript> + + +
+
+ + + + + + + + + + +

start() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start the speech recognition process.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the process actually starts

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

stop() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop the speech recognition process.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the process actually stops

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/TextBox.html b/docs/TextBox.html new file mode 100644 index 0000000..c3a61a6 --- /dev/null +++ b/docs/TextBox.html @@ -0,0 +1,4353 @@ + + + + + + TextBox - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

TextBox

+ + + + + + + +
+ +
+ +

+ visual + + TextBox +

+ + +
+ +
+ +
+ + + + + +

new TextBox(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
    + +
  • ColorMixin
  • + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

text + + +string + + + + + + <optional>
+ + + + + +
+ + "" + +

the text to be rendered

font + + +string + + + + + + <optional>
+ + + + + +
+ + "Arial" + +

the font family

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the text

color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('white') + +

color of the text

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth (i.e. the z order)

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the text size and position

ori + + +number + + + + + + <optional>
+ + + + + +
+ + 0.0 + +

the orientation (in degrees)

letterHeight + + +number + + + + + + <optional>
+ + + + + +
+ + <default value> + +

the height of the text

bold + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the text is bold

italic + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the text is italic

anchor + + +string + + + + + + <optional>
+ + + + + +
+ + 'left' + +

horizontal alignment

multiline + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not a multiline element is used

autofocus + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not the first input should receive focus by default

flipHoriz + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip the text horizontally

flipVert + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip the text vertically

fillColor + + +Color + + + + + + <optional>
+ + + + + +
+ +

fill color of the text-box

languageStyle + + +String + + + + + + <optional>
+ + + + + +
+ + "LTR" + +

sets the direction property of the text inputs. Possible values ["LTR", "RTL", "Arabic"]. "Arabic" is added for consistency with PsychoPy

borderColor + + +Color + + + + + + <optional>
+ + + + + +
+ +

border color of the text-box

clipMask + + +PIXI.Graphics + + + + + + <optional>
+ + + + + +
+ + null + +

the clip mask

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

fitToContent + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to resize itself automaitcally to fit to the text content

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static, readonly) _defaultLetterHeightMap

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates units to default letter height.

+
+ + + + + + + + + + +

(protected, static, readonly) _defaultSizeMap

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates units to default sizes.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _addEventListeners()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add event listeners to text-box object. Method is called internally upon object construction.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getAnchor() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert the anchor attribute into numerical values.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the anchor, as an array of numbers in [0,1]
  • +
+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _getDefaultLetterHeight() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the default letter height given the stimulus' units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the letter height corresponding to this stimulus' units.
  • +
+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

(protected) _getTextInputOptions()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the TextInput options applied to the PIXI.TextInput.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • take size into account
  • +
+
+ +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

clear()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clears the current text value.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getText() → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

For accessing the underlying input value.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the current text value of the underlying input element.
  • +
+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

reset()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Clears the current text value or sets it back to match the placeholder.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setAlignment(alignment, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the alignment attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
alignment + + +boolean + + + + + + + + + + + + left + +

alignment of the text

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setAnchor(anchor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the anchor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
anchor + + +boolean + + + + + + + + + + + + center + +

anchor of the textbox

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setBorderColor(borderColor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the borderColor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
borderColor + + +Color + + + + + + + + + + + +

border color of the text box

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setColor(color, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the color attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
color + + +boolean + + + + + + + + + + + +

color of the text

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFillColor(fillColor, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the fillColor attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fillColor + + +boolean + + + + + + + + + + + +

fill color of the text box

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFitToContent(fitToContent, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the fitToContent attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fitToContent + + +boolean + + + + + + + + + + + +

whether or not to autoresize textbox to fit to text content

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setFont(font, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the font for textbox.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
font + + +string + + + + + + + + + + + + Arial + +

the font family

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLanguageStyle(languageStyle, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the languageStyle attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
languageStyle + + +String + + + + + + + + + + + + LTR + +

text direction in textbox, accepts values ["LTR", "RTL", "Arabic"]

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLetterHeight(fontSizeopt, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set letterHeight (font size) for textbox.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fontSize + + +string + + + + + + <optional>
+ + + + + +
+ + <default value> + +

the size of the font

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setSize(size, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the size attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
size + + +boolean + + + + + + + + + + + +

whether or not to wrap the text at the given width

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ + + + + + + + + + + + + + + + + + + + + + + + +

setText(text)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

For tweaking the underlying input value.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +string + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/TextStim.html b/docs/TextStim.html new file mode 100644 index 0000000..b77c618 --- /dev/null +++ b/docs/TextStim.html @@ -0,0 +1,2296 @@ + + + + + + TextStim - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

TextStim

+ + + + + + + +
+ +
+ +

+ visual + + TextStim +

+ +

TextStim handles text stimuli.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new TextStim(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + +
Mixes In:
+ +
    + +
  • ColorMixin
  • + +
+ + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • vertical alignment, and orientation are currently NOT implemented
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
name + + +String + + + + + + + + + + + +

the name used when logging messages from this stimulus

win + + +module:core.Window + + + + + + + + + + + +

the associated Window

text + + +string + + + + + + <optional>
+ + + + + +
+ + "Hello World" + +

the text to be rendered

font + + +string + + + + + + <optional>
+ + + + + +
+ + "Arial" + +

the font family

pos + + +Array.<number> + + + + + + <optional>
+ + + + + +
+ + [0, 0] + +

the position of the center of the text

color + + +Color + + + + + + <optional>
+ + + + + +
+ + 'white' + +

the background color

opacity + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the opacity

depth + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

the depth (i.e. the z order)

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

the contrast

units + + +string + + + + + + <optional>
+ + + + + +
+ + "norm" + +

the units of the text size and position

ori + + +number + + + + + + + + + + + +

the orientation (in degrees)

height + + +number + + + + + + <optional>
+ + + + + +
+ + 0.1 + +

the height of the text

bold + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the text is bold

italic + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the text is italic

alignHoriz + + +string + + + + + + <optional>
+ + + + + +
+ + 'center' + +

horizontal alignment

alignVert + + +string + + + + + + <optional>
+ + + + + +
+ + 'center' + +

vertical alignment

wrapWidth + + +boolean + + + + + + + + + + + +

whether or not to wrap the text horizontally

flipHoriz + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip the text horizontally

flipVert + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to flip the text vertically

clipMask + + +PIXI.Graphics + + + + + + <optional>
+ + + + + +
+ + null + +

the clip mask

autoDraw + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not the stimulus should be automatically drawn on every frame flip

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • VisualStim
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

(protected, static, readonly) _defaultLetterHeightMap

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates units to default letter height.

+
+ + + + + + + + + + +

(protected, static, readonly) _defaultWrapWidthMap

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This map associates units to default wrap width.

+
+ + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _estimateBoundingBox()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the bounding box.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getAnchor() → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert the alignment attributes into an anchor.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the anchor
  • +
+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

(protected) _getDefaultLetterHeight()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the default letter height given the stimulus' units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getDefaultWrapWidth()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the default wrap width given the stimulus' units.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _getTextStyle()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the PIXI Text Style applied to the PIXI.Text

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update the stimulus, if necessary.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) getBoundingBox(tightopt) → {Array.<number>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the bounding gox.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
tight + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to fit as closely as possible to the text

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the bounding box, in the units of this TextStim
  • +
+
+ + + +
+
+ Type +
+
+ +Array.<number> + + +
+
+ + + + + + + + + + +

getTextMetrics()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the metrics estimated for the text and style.

+

Note: getTextMetrics does not require the PIXI representation of the stimulus +to be instantiated, unlike getSize().

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

setColor(color, logopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the color attribute.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
color + + +undefined +| + +null +| + +number + + + + + + + + + + + +

the color

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether of not to log

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/TonePlayer.html b/docs/TonePlayer.html new file mode 100644 index 0000000..94dc9ce --- /dev/null +++ b/docs/TonePlayer.html @@ -0,0 +1,1657 @@ + + + + + + TonePlayer - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

TonePlayer

+ + + + + + + +
+ +
+ +

+ sound + + TonePlayer +

+ +

This class handles the playing of tones.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new TonePlayer(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

This class handles the playing of tones.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

duration_s + + +number + + + + + + <optional>
+ + + + + +
+ + 0.5 + +

duration of the tone (in seconds). If duration_s == -1, the sound will play indefinitely.

note + + +string +| + +number + + + + + + <optional>
+ + + + + +
+ + 'C4' + +

note (if string) or frequency (if number)

volume + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

volume of the tone (must be between 0 and 1.0)

loops + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

how many times to repeat the tone after it has played once. If loops == -1, the tone will repeat indefinitely until stopped.

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

(static) SoundLibrary :Object

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + + + + + + +

Methods

+ + + + + + +

(static) accept(sound) → {Object|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether this player can play the given sound.

+

Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, +we throw an exception.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sound + + +module:sound.Sound + + + +

the sound

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

an instance of TonePlayer that can play the given sound or undefined otherwise

+
+ + + +
+
+ Type +
+
+ +Object +| + +undefined + + +
+
+ + + + + + + + + + +

(protected) _initSoundLibrary()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Initialise the sound library.

+

Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, +we throw an exception.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getDuration() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the sound.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the duration of the sound, in seconds

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

play(loopsopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
loops + + +boolean + + + + + + <optional>
+ + + + + +

how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

setDuration(duration_s)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the duration of the tone.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
duration_s + + +number + + + +

the duration of the tone (in seconds) If duration_s == -1, the sound will play indefinitely.

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLoops(loops)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the number of loops.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loops + + +number + + + +

how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

setVolume(volume, muteopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the volume of the tone.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
volume + + +Integer + + + + + + + + + + + +

the volume of the tone

mute + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to mute the tone

+ + + + + + + + + + + + + + + + + + + + + + + + +

stop()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the sound immediately.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/TrackPlayer.html b/docs/TrackPlayer.html new file mode 100644 index 0000000..952f3d0 --- /dev/null +++ b/docs/TrackPlayer.html @@ -0,0 +1,1682 @@ + + + + + + TrackPlayer - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

TrackPlayer

+ + + + + + + +
+ +
+ +

+ sound + + TrackPlayer +

+ +

This class handles the playback of sound tracks.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new TrackPlayer(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • stopTime is currently not implemented (tracks will play from startTime to finish)
  • + +
  • stereo is currently not implemented
  • +
+
+ +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

howl + + +Object + + + + + + + + + + + +

the sound object (see https://howlerjs.com/)

startTime + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

start of playback (in seconds)

stopTime + + +number + + + + + + <optional>
+ + + + + +
+ + -1 + +

end of playback (in seconds)

stereo + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to play the sound or track in stereo

volume + + +number + + + + + + <optional>
+ + + + + +
+ + 1.0 + +

volume of the sound (must be between 0 and 1.0)

loops + + +number + + + + + + <optional>
+ + + + + +
+ + 0 + +

how many times to repeat the track or tone after it has played

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + + + + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(static) accept(sound) → {Object|undefined}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Determine whether this player can play the given sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sound + + +module:sound.Sound + + + +

the sound, which should be the name of an audio resource +file

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

an instance of TrackPlayer that can play the given track or undefined otherwise

+
+ + + +
+
+ Type +
+
+ +Object +| + +undefined + + +
+
+ + + + + + + + + + +

getDuration() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the sound, in seconds.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the duration of the track, in seconds

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

play(loops, fadeDurationopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start playing the sound.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
loops + + +number + + + + + + + + + + + +

how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.

fadeDuration + + +number + + + + + + <optional>
+ + + + + +
+ + 17 + +

how long should the fading in last in ms

+ + + + + + + + + + + + + + + + + + + + + + + + +

setDuration(duration_s)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the duration of the track.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
duration_s + + +number + + + +

the duration of the track in seconds

+ + + + + + + + + + + + + + + + + + + + + + + + +

setLoops(loops)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the number of loops.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
loops + + +number + + + +

how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.

+ + + + + + + + + + + + + + + + + + + + + + + + +

setVolume(volume, muteopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the volume of the tone.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
volume + + +Integer + + + + + + + + + + + +

the volume of the track (must be between 0 and 1.0)

mute + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to mute the track

+ + + + + + + + + + + + + + + + + + + + + + + + +

stop(fadeDurationopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the sound immediately.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
fadeDuration + + +number + + + + + + <optional>
+ + + + + +
+ + 17 + +

how long should the fading out last in ms

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/Transcript.html b/docs/Transcript.html new file mode 100644 index 0000000..b196e51 --- /dev/null +++ b/docs/Transcript.html @@ -0,0 +1,323 @@ + + + + + + Transcript - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Transcript

+ + + + + + + +
+ +
+ +

+ Transcript +

+ +

Transcript.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Transcript(transcriber, text, confidence)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Object holding a transcription result.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
transcriber + + +SpeechRecognition + + + + + +

the transcriber

text + + +string + + + + + +

the transcript

confidence + + +number + + + + + + 0 + +

confidence in the transcript

+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +

Classes

+ +
+
Transcript
+
+
+ + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/Window.html b/docs/Window.html new file mode 100644 index 0000000..abbc7eb --- /dev/null +++ b/docs/Window.html @@ -0,0 +1,2327 @@ + + + + + + Window - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Window

+ + + + + + + +
+ +
+ +

+ core + + Window +

+ +

Window displays the various stimuli of the experiment.

+

It sets up a PIXI renderer, which we use to render the experiment stimuli.

+ + +
+ +
+ +
+ + + + +

Constructor

+ + +

new Window(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
psychoJS + + +module:core.PsychoJS + + + + + + + + + + + +

the PsychoJS instance

name + + +string + + + + + + <optional>
+ + + + + +
+ +

the name of the window

fullscr + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to go fullscreen

color + + +Color + + + + + + <optional>
+ + + + + +
+ + Color('black') + +

the background color of the window

gamma + + +number + + + + + + <optional>
+ + + + + +
+ + 1 + +

sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma)

contrast + + +number + + + + + + <optional>
+ + + + + +
+ + 1 + +

sets the contrast value

units + + +string + + + + + + <optional>
+ + + + + +
+ + 'pix' + +

the units of the window

waitBlanking + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to wait for all rendering operations to be done +before flipping

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + +

Extends

+ + + + +
    +
  • PsychObject
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected, static) _resizePixiRenderer(pjsWindow, event)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Adjust the size of the renderer and the position of the root container +in response to a change in the browser's size.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pjsWindow + + +module:core.Window + + + +

the PsychoJS Window

event + +
+ + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _fullRefresh()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Force an update of all stimuli in this window's drawlist.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _refresh()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Recompute this window's draw list and _container children for the next animation frame.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _setupPixi()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setup PIXI.

+

A new renderer is created and a container is added to it. The renderer's touch and mouse events +are handled by the EventManager.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _updateIfNeeded()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Update this window, if need be.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _writeLogOnFlip()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Send all logged messages to the Logger.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

addPixiObject()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add PIXI.DisplayObject to the container displayed on the scene (window)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

adjustScreenSize()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Take the browser full screen if possible.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

callOnFlip(flipCallback, …flipCallbackArgs)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a callback function that will run after the next screen flip, i.e. immediately after the next rendering of the +Window.

+

This is typically used to reset a timer or clock.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
flipCallback + + +module:core.Window~OnFlipCallback + + + + + + + + + +

callback function.

flipCallbackArgs + + +* + + + + + + + + + + <repeatable>
+ +

arguments for the callback function.

+ + + + + + + + + + + + + + + + + + + + + + + + +

close()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Close the window.

+

Note: this actually only removes the canvas used to render the experiment stimuli.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

closeFullScreen()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Take the browser back from full screen if needed.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

getActualFrameRate() → {number}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Estimate the frame rate.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

rAF based delta time based approximation, 60.0 by default

+
+ + + +
+
+ Type +
+
+ +number + + +
+
+ + + + + + + + + + +

logOnFlip(options, levelopt, objopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Log a message.

+

Note: the message will be time-stamped at the next call to requestAnimationFrame.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
options + + +Object + + + + + + + + + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + +

the message to be logged

+ +
level + + +module:util.Logger.ServerLevel + + + + + + <optional>
+ + + + + +
+ + module:util.Logger.ServerLevel.EXP + +

the log level

obj + + +Object + + + + + + <optional>
+ + + + + +
+ +

the object associated with the message

+ + + + + + + + + + + + + + + + + + + + + + + + +

removePixiObject()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Remove PIXI.DisplayObject from the container displayed on the scene (window)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

render()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Render the stimuli onto the canvas.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:50 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/core_EventManager.js.html b/docs/core_EventManager.js.html index ee1a208..124bf9d 100644 --- a/docs/core_EventManager.js.html +++ b/docs/core_EventManager.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/EventManager.js - - - + core/EventManager.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/EventManager.js

+ + + + +
+ +

core/EventManager.js

+ @@ -30,8 +54,8 @@ * Manager handling the keyboard and mouse/touch events. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -39,16 +63,15 @@ import { Clock, MonotonicClock } from "../util/Clock.js"; import { PsychoJS } from "./PsychoJS.js"; /** - * @class * <p>This manager handles all participant interactions with the experiment, i.e. keyboard, mouse and touch events.</p> - * - * @name module:core.EventManager - * @class - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance */ export class EventManager { + /** + * @memberof module:core + * @param {Object} psychoJS + * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance + */ constructor(psychoJS) { this._psychoJS = psychoJS; @@ -85,9 +108,6 @@ export class EventManager * * <p>Note: The w3c [key-event viewer]{@link https://w3c.github.io/uievents/tools/key-event-viewer.html} can be used to see possible values for the items in the keyList given the user's keyboard and chosen layout. The "key" and "code" columns in the UI Events fields are the relevant values for the keyList argument.</p> * - * @name module:core.EventManager#getKeys - * @function - * @public * @param {Object} options * @param {string[]} [options.keyList= null] - keyList allows the user to specify a set of keys to check for. Only keypresses from this set of keys will be removed from the keyboard buffer. If no keyList is given, all keys will be checked and the key buffer will be cleared completely. * @param {boolean} [options.timeStamped= false] - If true will return a list of tuples instead of a list of keynames. Each tuple has (keyname, time). @@ -165,9 +185,6 @@ export class EventManager /** * Get the mouse info. * - * @name module:core.EventManager#getMouseInfo - * @function - * @public * @return {EventManager.MouseInfo} the mouse info. */ getMouseInfo() @@ -178,10 +195,6 @@ export class EventManager /** * Clear all events from the event buffer. * - * @name module:core.EventManager#clearEvents - * @function - * @public - * * @todo handle the attribs argument */ clearEvents(attribs) @@ -191,10 +204,6 @@ export class EventManager /** * Clear all keys from the key buffer. - * - * @name module:core.EventManager#clearKeys - * @function - * @public */ clearKeys() { @@ -204,10 +213,6 @@ export class EventManager /** * Start the move clock. * - * @name module:core.EventManager#startMoveClock - * @function - * @public - * * @todo not implemented */ startMoveClock() @@ -217,10 +222,6 @@ export class EventManager /** * Stop the move clock. * - * @name module:core.EventManager#stopMoveClock - * @function - * @public - * * @todo not implemented */ stopMoveClock() @@ -230,10 +231,6 @@ export class EventManager /** * Reset the move clock. * - * @name module:core.EventManager#resetMoveClock - * @function - * @public - * * @todo not implemented */ resetMoveClock() @@ -243,9 +240,6 @@ export class EventManager /** * Add various mouse listeners to the Pixi renderer of the {@link Window}. * - * @name module:core.EventManager#addMouseListeners - * @function - * @public * @param {PIXI.Renderer} renderer - The Pixi renderer */ addMouseListeners(renderer) @@ -347,9 +341,7 @@ export class EventManager /** * Add key listeners to the document. * - * @name module:core.EventManager#_addKeyListeners - * @function - * @private + * @protected */ _addKeyListeners() { @@ -387,9 +379,6 @@ export class EventManager * Convert a keylist that uses pyglet key names to one that uses W3C KeyboardEvent.code values. * <p>This allows key lists that work in the builder environment to work in psychoJS web experiments.</p> * - * @name module:core.EventManager#pyglet2w3c - * @function - * @public * @param {Array.string} pygletKeyList - the array of pyglet key names * @return {Array.string} the w3c keyList */ @@ -414,10 +403,6 @@ export class EventManager /** * Convert a W3C Key Code into a pyglet key. * - * @name module:core.EventManager#w3c2pyglet - * @function - * @public - * @static * @param {string} code - W3C Key Code * @returns {string} corresponding pyglet key */ @@ -437,10 +422,6 @@ export class EventManager * Convert a keycode to a W3C UI Event code. * <p>This is for legacy browsers.</p> * - * @name module:core.EventManager#keycode2w3c - * @function - * @public - * @static * @param {number} keycode - the keycode * @returns {string} corresponding W3C UI Event code */ @@ -458,9 +439,8 @@ export class EventManager * <p>Unfortunately, it is not very fine-grained: for instance, there is no difference between Alt Left and Alt * Right, or between Enter and Numpad Enter. Use at your own risk (or upgrade your browser...).</p> * - * @name module:core.EventManager#_keycodeMap * @readonly - * @private + * @protected * @type {Object.<number,String>} */ EventManager._keycodeMap = { @@ -546,9 +526,8 @@ EventManager._keycodeMap = { * This map associates pyglet key names to the corresponding W3C KeyboardEvent codes values. * <p>More information can be found [here]{@link https://www.w3.org/TR/uievents-code}</p> * - * @name module:core.EventManager#_pygletMap * @readonly - * @private + * @protected * @type {Object.<String,String>} */ EventManager._pygletMap = { @@ -647,9 +626,8 @@ EventManager._pygletMap = { /** * <p>This map associates W3C KeyboardEvent.codes to the corresponding pyglet key names. * - * @name module:core.EventManager#_reversePygletMap * @readonly - * @private + * @protected * @type {Object.<String,String>} */ EventManager._reversePygletMap = {}; @@ -657,8 +635,6 @@ EventManager._reversePygletMap = {}; /** * Utility class used by the experiment scripts to keep track of a clock and of the current status (whether or not we are currently checking the keyboard) * - * @name module:core.BuilderKeyResponse - * @class * @param {Object} options * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance */ @@ -682,19 +658,23 @@ export class BuilderKeyResponse + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_GUI.js.html b/docs/core_GUI.js.html index 0b0cdbf..6d863b1 100644 --- a/docs/core_GUI.js.html +++ b/docs/core_GUI.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/GUI.js - - - + core/GUI.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/GUI.js

+ + + + +
+ +

core/GUI.js

+ @@ -31,8 +55,8 @@ * * @author Alain Pitiot * @author Sijia Zhao - fine-grained resource loading - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2021.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -43,22 +67,37 @@ import { Scheduler } from "../util/Scheduler.js"; import * as util from "../util/Util.js"; import { PsychoJS } from "./PsychoJS.js"; import { ServerManager } from "./ServerManager.js"; +import A11yDialog from "a11y-dialog"; /** - * @class - * Graphic User Interface - * - * @name module:core.GUI - * @class - * @param {module:core.PsychoJS} psychoJS the PsychoJS instance + * <p>GUI manages the various pop-up dialog boxes that guide the participant, throughout the + * lifecycle of the experiment, e.g. at the start while the resources are downloading, or at the + * end when the data is uploading to the server</p> */ export class GUI { + /** + * Default settings for GUI. + * + * @type {Object} + */ + static DEFAULT_SETTINGS = { + DlgFromDict: { + // The dialog box shows an OK button. The button becomes enable when all registered resources + // have been downloaded. Participants must click on the OK button to move on with the experiment. + requireParticipantClick: true + } + }; + get dialogComponent() { return this._dialogComponent; } + /** + * @memberof module:core + * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance + */ constructor(psychoJS) { this._psychoJS = psychoJS; @@ -68,8 +107,6 @@ export class GUI { this._onResourceEvents(signal); }); - - this._dialogScalingFactor = 0; } /** @@ -86,37 +123,39 @@ export class GUI * <p>If the participant cancels (by pressing Cancel or by closing the dialog box), then * the dictionary remains unchanged.</p> * - * @name module:core.GUI#DlgFromDict - * @function - * @public * @param {Object} options * @param {String} [options.logoUrl] - Url of the experiment logo * @param {String} [options.text] - information text * @param {Object} options.dictionary - associative array of values for the participant to set * @param {String} options.title - name of the project + * @param {boolean} [options.requireParticipantClick=true] - whether the participant must click on the OK + * button, when it becomes enabled, to move on with the experiment */ DlgFromDict({ logoUrl, text, dictionary, title, + requireParticipantClick = GUI.DEFAULT_SETTINGS.DlgFromDict.requireParticipantClick }) { // get info from URL: const infoFromUrl = util.getUrlParameters(); - this._progressMsg = "&nbsp;"; this._progressBarMax = 0; this._allResourcesDownloaded = false; this._requiredKeys = []; this._setRequiredKeys = new Map(); + this._progressMessage = "&nbsp;"; + this._requireParticipantClick = requireParticipantClick; + this._dictionary = dictionary; - // prepare PsychoJS component: + // prepare a PsychoJS component: this._dialogComponent = {}; this._dialogComponent.status = PsychoJS.Status.NOT_STARTED; const dialogClock = new Clock(); - const self = this; + const self = this; return () => { const t = dialogClock.getTime(); @@ -128,38 +167,30 @@ export class GUI // if the experiment is licensed, and running on the license rather than on credit, // we use the license logo: - if ( - self._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER + if (self._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER && typeof self._psychoJS.config.experiment.license !== "undefined" && self._psychoJS.config.experiment.runMode === "LICENSE" - && typeof self._psychoJS.config.experiment.license.institutionLogo !== "undefined" - ) + && typeof self._psychoJS.config.experiment.license.institutionLogo !== "undefined") { logoUrl = self._psychoJS.config.experiment.license.institutionLogo; } - // prepare jquery UI dialog box: - let htmlCode = '<div id="expDialog" title="' + title + '">'; + // prepare the markup for the a11y-dialog: + let markup = "<div class='dialog-container' id='experiment-dialog' aria-hidden='true' role='alertdialog'>"; + markup += "<div class='dialog-overlay'></div>"; + // markup += "<div class='dialog-overlay' data-a11y-dialog-hide></div>"; + markup += "<div class='dialog-content'>"; - // uncomment for older version of the library: - // htmlCode += '<p style="font-size: 0.8em; padding: 0.5em; margin-bottom: 0.5em; color: #FFAA00; border: 1px solid #FFAA00;">&#9888; This experiment uses a deprecated version of the PsychoJS library. Consider updating to a newer version (e.g. by updating PsychoPy and re-exporting the experiment).</p>'+ + // alert title and close button: + markup += `<div id='experiment-dialog-title' class='dialog-title'><p>${title}</p><button id='dialogClose' class='dialog-close' data-a11y-dialog-hide aria-label='Cancel Experiment'>&times;</button></div>`; - // logo: + // logo, if need be: if (typeof logoUrl === "string") { - htmlCode += '<img id="dialog-logo" class="logo" alt="logo" src="' + logoUrl + '">'; - } - - // information text: - if (typeof text === "string" && text.length > 0) - { - htmlCode += "<p>" + text + "</p>"; + markup += '<img id="dialog-logo" class="logo" alt="logo" src="' + logoUrl + '">'; } // add a combobox or text areas for each entry in the dictionary: - - // These may include Symbols as opposed to when using a for...in loop, - // but only strings are allowed in PsychoPy Object.keys(dictionary).forEach((key, keyIdx) => { const value = dictionary[key]; @@ -180,7 +211,7 @@ export class GUI if (!inUrl) { - htmlCode += '<label for="' + keyId + '">' + key + "</label>"; + markup += `<label for='${keyId}'> ${key} </label>`; // if the field is required: if (key.slice(-1) === "*") @@ -191,45 +222,76 @@ export class GUI // if value is an array, we create a select drop-down menu: if (Array.isArray(value)) { - htmlCode += '<select name="' + key + '" id="' + keyId + '" class="text ui-widget-content' - + ' ui-corner-all">'; + markup += `<select name='${key}' id='${keyId}' class='text'>`; // if the field is required, we add an empty option and select it: if (key.slice(-1) === "*") { - htmlCode += "<option disabled selected>...</option>"; + markup += "<option disabled selected>...</option>"; } for (const option of value) { - htmlCode += "<option>" + option + "</option>"; + markup += `<option> ${option} </option>`; } - htmlCode += "</select>"; - jQuery("#" + keyId).selectmenu({ classes: {} }); + markup += "</select>"; } - // otherwise we use a single string input: - /*if (typeof value === 'string')*/ + // otherwise we use a single string input: + //if (typeof value === 'string') else { - htmlCode += '<input type="text" name="' + key + '" id="' + keyId; - htmlCode += '" value="' + value + '" class="text ui-widget-content ui-corner-all">'; + markup += `<input type='text' name='${key}' id='${keyId}' value='${value}' class='text'>`; } } }); - if (this._requiredKeys.length > 0) + if (self._requiredKeys.length > 0) { - htmlCode += '<p class="validateTips">Fields marked with an asterisk (*) are required.</p>'; + markup += "<p class='validateTips'>Fields marked with an asterisk (*) are required.</p>"; } - // add a progress bar: - htmlCode += '<hr><div id="progressMsg" class="progress">' + self._progressMsg + "</div>"; - htmlCode += '<div id="progressbar"></div></div>'; + // progress bar: + markup += `<hr><div id='progressMsg' class='progress-msg'>${self._progressMessage}</div>`; + markup += "<div class='progress-container'><div id='progressBar' class='progress-bar'></div></div>"; - // replace root by the html code: + // buttons: + markup += "<hr>"; + markup += "<button id='dialogCancel' class='dialog-button' aria-label='Cancel Experiment'>Cancel</button>"; + if (self._requireParticipantClick) + { + markup += "<button id='dialogOK' class='dialog-button disabled' aria-label='Start Experiment'>Ok</button>"; + } + + markup += "</div></div>"; + + // replace root by the markup code: const dialogElement = document.getElementById("root"); - dialogElement.innerHTML = htmlCode; + dialogElement.innerHTML = markup; + + // init and open the dialog box: + const dialogDiv = document.getElementById("experiment-dialog"); + self._dialog = new A11yDialog(dialogDiv); + self._dialog.show(); + + // button callbacks: + self._dialogComponent.button = "Cancel"; + self._cancelButton = document.getElementById("dialogCancel"); + self._cancelButton.onclick = self._onCancelExperiment.bind(self); + if (self._requireParticipantClick) + { + self._okButton = document.getElementById("dialogOK"); + self._okButton.onclick = self._onStartExperiment.bind(self); + } + self._closeButton = document.getElementById("dialogClose"); + self._closeButton.onclick = self._onCancelExperiment.bind(self); + + // update the OK button status: + self._updateDialog(); + + self._progressMsg = document.getElementById("progressMsg"); + self._progressBar = document.getElementById("progressBar"); + self._updateProgressBar(); // setup change event handlers for all required keys: this._requiredKeys.forEach((keyId) => @@ -240,79 +302,6 @@ export class GUI input.oninput = (event) => GUI._onKeyChange(self, event); } }); - - // init and open the dialog box: - self._dialogComponent.button = "Cancel"; - jQuery("#expDialog").dialog({ - width: "500", - - autoOpen: true, - modal: false, - closeOnEscape: false, - resizable: false, - draggable: false, - - buttons: [ - { - id: "buttonCancel", - text: "Cancel", - click: function() - { - self._dialogComponent.button = "Cancel"; - jQuery("#expDialog").dialog("close"); - }, - }, - { - id: "buttonOk", - text: "Ok", - click: function() - { - // update dictionary: - Object.keys(dictionary).forEach((key, keyIdx) => - { - const input = document.getElementById("form-input-" + keyIdx); - if (input) - { - dictionary[key] = input.value; - } - }); - - self._dialogComponent.button = "OK"; - jQuery("#expDialog").dialog("close"); - - // Tackle browser demands on having user action initiate audio context - Tone.start(); - - // switch to full screen if requested: - self._psychoJS.window.adjustScreenSize(); - - // Clear events (and keypresses) accumulated during the dialog - self._psychoJS.eventManager.clearEvents(); - }, - }, - ], - - // close is called by both buttons and when the user clicks on the cross: - close: function() - { - // jQuery.unblockUI(); - jQuery(this).dialog("destroy").remove(); - self._dialogComponent.status = PsychoJS.Status.FINISHED; - }, - }) - // change colour of title bar - .prev(".ui-dialog-titlebar").css("background", "green"); - - // update the OK button status: - self._updateOkButtonStatus(); - - // block UI until user has pressed dialog button: - // note: block UI does not allow for text to be entered in the dialog form boxes, alas! - // jQuery.blockUI({ message: "", baseZ: 1}); - - // show dialog box: - jQuery("#progressbar").progressbar({ value: self._progressBarCurrentValue }); - jQuery("#progressbar").progressbar("option", "max", self._progressBarMax); } if (self._dialogComponent.status === PsychoJS.Status.FINISHED) @@ -334,9 +323,6 @@ export class GUI * * <p>This function can be used to display both warning and error messages.</p> * - * @name module:core.GUI#dialog - * @function - * @public * @param {Object} options * @param {string} options.message - the message to be displayed * @param {Object.<string, *>} options.error - an exception @@ -349,14 +335,16 @@ export class GUI warning, error, showOK = true, - onOK, + onOK } = {}) { // close the previously opened dialog box, if there is one: this.closeDialog(); - let htmlCode; - let titleColour; + // prepare the markup for the a11y-dialog: + let markup = "<div class='dialog-container' id='experiment-dialog' aria-hidden='true' role='alertdialog'>"; + markup += "<div class='dialog-overlay'></div>"; + markup += "<div class='dialog-content'>"; // we are displaying an error: if (typeof error !== "undefined") @@ -369,9 +357,8 @@ export class GUI error = "Unspecified JavaScript error"; } - let errorCode = null; - // go through the error stack and look for errorCode if there is one: + let errorCode = null; let stackCode = "<ul>"; while (true) { @@ -403,101 +390,206 @@ export class GUI if (errorCode) { const error = this._userFriendlyError(errorCode); - htmlCode = error.htmlCode; - titleColour = error.titleColour; + markup += `<div id='experiment-dialog-title' class='dialog-title ${error.class}'><p>${error.title}</p></div>`; + markup += `<p>${error.text}</p>`; } else { - htmlCode = '<div id="msgDialog" title="Error">'; - htmlCode += '<p class="validateTips">Unfortunately we encountered the following error:</p>'; - htmlCode += stackCode; - htmlCode += "<p>Try to run the experiment again. If the error persists, contact the experiment designer.</p>"; - htmlCode += "</div>"; - - titleColour = "red"; + markup += `<div id='experiment-dialog-title' class='dialog-title dialog-error'><p>Error</p></div>`; + markup += `<p>Unfortunately we encountered the following error:</p>`; + markup += stackCode; + markup += "<p>Try to run the experiment again. If the error persists, contact the experiment designer.</p>"; } } - // we are displaying a message: - else if (typeof message !== "undefined") - { - htmlCode = '<div id="msgDialog" title="Message">' - + '<p class="validateTips">' + message + "</p>" - + "</div>"; - titleColour = "green"; - } + // we are displaying a warning: else if (typeof warning !== "undefined") { - htmlCode = '<div id="msgDialog" title="Warning">' - + '<p class="validateTips">' + warning + "</p>" - + "</div>"; - titleColour = "orange"; + markup += `<div id='experiment-dialog-title' class='dialog-title dialog-warning'><p>Warning</p></div>`; + markup += `<p>${warning}</p>`; } - // replace root by the html code: + // we are displaying a message: + else if (typeof message !== "undefined") + { + markup += `<div id='experiment-dialog-title' class='dialog-title'><p>Message</p></div>`; + markup += `<p>${message}</p>`; + } + + if (showOK) + { + markup += "<hr><button id='dialogOK' class='dialog-button' aria-label='Close dialog'>Ok</button>"; + } + markup += "</div></div>"; + + // replace root by the markup code: const dialogElement = document.getElementById("root"); - dialogElement.innerHTML = htmlCode; + dialogElement.innerHTML = markup; // init and open the dialog box: - const self = this; - jQuery("#msgDialog").dialog({ - dialogClass: "no-close", + const dialogDiv = document.getElementById("experiment-dialog"); + this._dialog = new A11yDialog(dialogDiv); + this._dialog.show(); - width: "500", + // button callbacks: + if (showOK) + { + this._okButton = document.getElementById("dialogOK"); + this._okButton.onclick = () => + { + this.closeDialog(); - autoOpen: true, - modal: false, - closeOnEscape: false, - resizable: false, - draggable: false, - - buttons: (!showOK) ? [] : [{ - id: "buttonOk", - text: "Ok", - click: function() + // execute callback function: + if (typeof onOK !== "undefined") { - jQuery(this).dialog("destroy").remove(); + onOK(); + } + }; + } + } - // execute callback function: - if (typeof onOK !== "undefined") - { - onOK(); - } - }, - }], - }) - // change colour of title bar - .prev(".ui-dialog-titlebar").css("background", titleColour); + /** + * <p>Create a dialog box with a progress bar, to inform the participant of + * the last stages of the experiment: upload of results, of log, and closing + * of session.</p> + * + * @param {Object} options + * @param {String} [options.text] - information text + */ + finishDialog({ text = "", nbSteps = 0 }) + { + this.closeDialog(); + + // prepare the markup for the a11y-dialog: + let markup = "<div class='dialog-container' id='experiment-dialog' aria-hidden='true' role='alertdialog'>"; + markup += "<div class='dialog-overlay'></div>"; + markup += "<div class='dialog-content'>"; + markup += `<div id='experiment-dialog-title' class='dialog-title dialog-warning'><p>Warning</p></div>`; + markup += `<p>${text}</p>`; + + // progress bar: + markup += `<hr><div id='progressMsg' class='progress-msg'>&nbsp;</div>`; + markup += "<div class='progress-container'><div id='progressBar' class='progress-bar'></div></div>"; + + markup += "</div></div>"; + + // replace root by the markup code: + const dialogElement = document.getElementById("root"); + dialogElement.innerHTML = markup; + + // init and open the dialog box: + const dialogDiv = document.getElementById("experiment-dialog"); + this._dialog = new A11yDialog(dialogDiv); + this._dialog.show(); + + this._progressMsg = document.getElementById("progressMsg"); + this._progressBar = document.getElementById("progressBar"); + + this._progressMessage = "&nbsp;"; + this._progressBarCurrentValue = 0; + this._progressBarMax = nbSteps; + this._updateProgressBar(); + } + + finishDialogNextStep(text) + { + this._setProgressMessage(text); + ++ this._progressBarCurrentValue; + this._updateProgressBar(); } /** * Close the previously opened dialog box, if there is one. - * - * @name module:core.GUI#closeDialog - * @function - * @public */ closeDialog() { - const expDialog = jQuery("#expDialog"); - if (expDialog.length) + if (this._dialog) { - expDialog.dialog("destroy").remove(); - } - const msgDialog = jQuery("#msgDialog"); - if (msgDialog.length) - { - msgDialog.dialog("destroy").remove(); + this._dialog.hide(); } } /** - * Listener for resource event from the [Server Manager]{@link ServerManager}. + * Set the progress message. * - * @name module:core.GUI#_onResourceEvents - * @function - * @private - * @param {Object.<string, string|Symbol>} signal the signal + * @protected + * @param {string} message the message + */ + _setProgressMessage(message) + { + this._progressMessage = message; + if (typeof this._progressMsg !== "undefined") + { + this._progressMsg.innerText = message; + } + } + + /** + * Update the progress bar. + * + * @protected + */ + _updateProgressBar() + { + if (typeof this._progressBar !== "undefined") + { + this._progressBar.style.width = `${Math.round(this._progressBarCurrentValue * 100.0 / this._progressBarMax)}%`; + } + } + + /** + * Callback triggered when the participant presses the Cancel button + * + * @protected + */ + _onCancelExperiment() + { + this._dialogComponent.button = "Cancel"; + + this._dialog.hide(); + this._dialog = null; + this._dialogComponent.status = PsychoJS.Status.FINISHED; + } + + /** + * Callback triggered when the participant presses the OK button + * + * @protected + */ + _onStartExperiment() + { + this._dialogComponent.button = "OK"; + + // update the dictionary: + Object.keys(this._dictionary).forEach((key, keyIdx) => + { + const input = document.getElementById("form-input-" + keyIdx); + if (input) + { + this._dictionary[key] = input.value; + } + }); + + + // Start Tone here, since a user action is required to initiate the audio context: + Tone.start(); + + // switch to full screen if requested: + this._psychoJS.window.adjustScreenSize(); + + // clear all events (and keypresses) accumulated until now: + this._psychoJS.eventManager.clearEvents(); + + this._dialog.hide(); + this._dialog = null; + this._dialogComponent.status = PsychoJS.Status.FINISHED; + } + + /** + * Callback triggered upon a resource event from the [Server Manager]{@link module:core.ServerManager}. + * + * @protected + * @param {Object.<string, string|Symbol>} signal - the ServerManager's signal */ _onResourceEvents(signal) { @@ -508,16 +600,19 @@ export class GUI { // for each resource, we have a 'downloading resource' and a 'resource downloaded' message: this._progressBarMax = signal.count * 2; - jQuery("#progressbar").progressbar("option", "max", this._progressBarMax); - this._progressBarCurrentValue = 0; + this._updateProgressBar(); } // all the resources have been downloaded: show the ok button else if (signal.message === ServerManager.Event.DOWNLOAD_COMPLETED) { this._allResourcesDownloaded = true; - jQuery("#progressMsg").text("all resources downloaded."); - this._updateOkButtonStatus(); + this._progressBarMax = 100; + this._progressBarCurrentValue = 100; + this._updateProgressBar(); + this._setProgressMessage("all resources downloaded."); + + this._updateDialog(); } // update progress bar: else if ( @@ -533,68 +628,75 @@ export class GUI if (signal.message === ServerManager.Event.RESOURCE_DOWNLOADED) { - jQuery("#progressMsg").text("downloaded " + (this._progressBarCurrentValue / 2) + " / " + (this._progressBarMax / 2)); + this._setProgressMessage(`downloaded ${this._progressBarCurrentValue / 2} / ${this._progressBarMax / 2}`); } else { - jQuery("#progressMsg").text("downloading " + (this._progressBarCurrentValue / 2) + " / " + (this._progressBarMax / 2)); + this._setProgressMessage(`downloading ${this._progressBarCurrentValue / 2} / ${this._progressBarMax / 2}`); } - // $("#progressMsg").text(signal.resource + ': downloaded.'); - jQuery("#progressbar").progressbar("option", "value", this._progressBarCurrentValue); + + this._updateProgressBar(); } // unknown message: we just display it else { - jQuery("#progressMsg").text(signal.message); + this._progressMsg.innerHTML = signal.message; } } /** - * Update the status of the OK button. + * Update the dialog box. * - * @name module:core.GUI#_updateOkButtonStatus - * @param [changeFocus = false] - whether or not to change the focus to the OK button - * @function - * @private + * @protected + * @param [changeOKButtonFocus = false] - whether to change the focus to the OK button */ - _updateOkButtonStatus(changeFocus = true) + _updateDialog(changeOKButtonFocus = true) { - if ( - (this._psychoJS.getEnvironment() === ExperimentHandler.Environment.LOCAL) - || (this._allResourcesDownloaded && this._setRequiredKeys && this._setRequiredKeys.size >= this._requiredKeys.length) - ) + const allRequirementsFulfilled = this._allResourcesDownloaded + && (this._setRequiredKeys && this._setRequiredKeys.size >= this._requiredKeys.length); + + // if the participant is required to click on the OK button: + if (this._requireParticipantClick) { - if (changeFocus) + if (typeof this._okButton !== "undefined") { - jQuery("#buttonOk").button("option", "disabled", false).focus(); + // locally the OK button is always enabled, otherwise only if all requirements have been fulfilled: + if (this._psychoJS.getEnvironment() === ExperimentHandler.Environment.LOCAL || allRequirementsFulfilled) + { + if (changeOKButtonFocus) + { + this._okButton.classList = ["dialog-button"]; + this._okButton.focus(); + } + else + { + this._okButton.classList = ["dialog-button"]; + } + } + else + { + this._okButton.classList = ["dialog-button", "disabled"]; + } } - else - { - jQuery("#buttonOk").button("option", "disabled", false); - } - } - else - { - jQuery("#buttonOk").button("option", "disabled", true); + + return; } - // strangely, changing the disabled option sometimes fails to update the ui, - // so we need to hide it and show it again: - jQuery("#buttonOk").hide(0, () => + + // if all requirements are fulfilled and the participant is not required to click on the OK button, + // then we close the dialog box and move on with the experiment: + if (allRequirementsFulfilled) { - jQuery("#buttonOk").show(); - }); + this._onStartExperiment(); + } } /** - * Listener for change event for required keys. + * Callback triggered upon change event (for required keys). * - * @name module:core.GUI#_onKeyChange - * @function - * @static - * @private + * @protected * @param {module:core.GUI} gui - this GUI - * @param {Event} event - event + * @param {Event} event - the key's event */ static _onKeyChange(gui, event) { @@ -610,15 +712,15 @@ export class GUI gui._setRequiredKeys.delete(event.target); } - gui._updateOkButtonStatus(false); + gui._updateDialog(false); } /** - * Get a more user-friendly html message. + * Get the user-friendly html message associated to a pavlovia.or server error code. * + * @protected * @param {number} errorCode - the pavlovia.org server error code - * @private - * @return {{htmlCode: string, titleColour: string}} a user-friendly error message + * @return {{class: string, title: string, text: string}} a user-friendly error message */ _userFriendlyError(errorCode) { @@ -627,130 +729,101 @@ export class GUI // INTERNAL_ERROR case 1: return { - htmlCode: - '<div id="msgDialog" title="Error"><p>Oops we encountered an internal server error.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p></div>', - titleColour: "red", + class: "dialog-error", + title: "Error", + text: "<p>Oops we encountered an <strong>internal server error</strong>.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p>" }; // MONGODB_ERROR - case 2: return { - htmlCode: - '<div id="msgDialog" title="Error"><p>Oops we encountered a database error.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p></div>', - titleColour: "red", + class: "dialog-error", + title: "Error", + text: "<p>Oops we encountered a <strong>database error</strong>.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p>" }; // STATUS_NONE - case 20: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any status and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any status and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p>` }; // STATUS_INACTIVE - case 21: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently inactive and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently inactive and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p>` }; // STATUS_DELETED - case 22: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been deleted and cannot be run.</p><p>If you are the experiment designer, either go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING, or generate a new experiment.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been deleted and cannot be run any longer.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been deleted and cannot be run.</p><p>If you are the experiment designer, either go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING, or generate a new experiment.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been deleted and cannot be run any longer.</p>` }; // STATUS_ARCHIVED - case 23: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been archived and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been archived and cannot be run at the moment.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been archived and cannot be run.</p><p>If you are the experiment designer, go to your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been archived and cannot be run at the moment.</p>` }; // PILOTING_NO_TOKEN - case 30: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently in PILOTING mode but the pilot token is missing from the URL.</p><p>If you are the experiment designer, you can pilot it by pressing the pilot button on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently in PILOTING mode but the pilot token is missing from the URL.</p><p>If you are the experiment designer, you can pilot it by pressing the pilot button on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p>` }; // PILOTING_INVALID_TOKEN - case 31: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> cannot be run because the pilot token in the URL is invalid, possibly because it has expired.</p><p>If you are the experiment designer, you can generate a new token by pressing the pilot button on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> cannot be run because the pilot token in the URL is invalid, possibly because it has expired.</p><p>If you are the experiment designer, you can generate a new token by pressing the pilot button on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p>` }; // LICENSE_EXPIRED - case 50: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that has expired. </p><p>If you are the experiment designer, you can either contact the license manager to inquire about the expiration, or you can run your experiments using credits. You will find all relevant details about the license on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>, where you will also be able to change its running mode to CREDIT.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license having expired.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that has expired. </p><p>If you are the experiment designer, you can either contact the license manager to inquire about the expiration, or you can run your experiments using credits. You will find all relevant details about the license on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>, where you will also be able to change its running mode to CREDIT.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license having expired.</p>` }; // LICENSE_APPROVAL_NEEDED - case 51: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that requires one or more documents to be approved before the experiment can be run. </p><p>If you are the experiment designer, please contact the license manager and ask him or her which documents must be approved. You will find all relevant details about the license on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license requiring documents to be approved.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that requires one or more documents to be approved before the experiment can be run. </p><p>If you are the experiment designer, please contact the license manager and ask him or her which documents must be approved. You will find all relevant details about the license on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license requiring documents to be approved.</p>` }; // CREDIT_NOT_ENOUGH - case 60: return { - htmlCode: - `<div id="msgDialog" title="Warning"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any assigned credit left and cannot be run.</p><p>If you are the experiment designer, you can assign more credits to it on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment requires more assigned credits to run.</p></div>`, - titleColour: "orange", + class: "dialog-warning", + title: "Warning", + text: `<p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any assigned credit left and cannot be run.</p><p>If you are the experiment designer, you can assign more credits to it on your <a href="https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment requires more assigned credits to run.</p>` }; default: return { - htmlCode: - `<div id="msgDialog" title="Error"><p>Unfortunately we encountered an unspecified error (error code: ${errorCode}.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p></div>`, - titleColour: "red", + class: "dialog-error", + title: "Error", + text: `<p>Unfortunately we encountered an unspecified error (error code: ${errorCode}.</p><p>Try to run the experiment again. If the error persists, contact the experiment designer.</p>` }; } } } -/** - * Maximal dimensions of the dialog window. - * - * @name module:core.GUI#dialogMaxSize - * @enum {Symbol} - * @readonly - * @public - */ -GUI.dialogMaxSize = [500, 600]; - -/** - * Dialog window margins. - * - * @name module:core.GUI#dialogMargin - * @enum {Symbol} - * @readonly - * @public - */ -GUI.dialogMargin = [50, 50];
@@ -758,19 +831,23 @@ GUI.dialogMargin = [50, 50]; + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_Keyboard.js.html b/docs/core_Keyboard.js.html index 9ccb9b1..0b59d26 100644 --- a/docs/core_Keyboard.js.html +++ b/docs/core_Keyboard.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/Keyboard.js - - - + core/Keyboard.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/Keyboard.js

+ + + + +
+ +

core/Keyboard.js

+ @@ -30,8 +54,8 @@ * Manager handling the keyboard events. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -41,15 +65,16 @@ import { EventManager } from "./EventManager.js"; import { PsychoJS } from "./PsychoJS.js"; /** - * @name module:core.KeyPress - * @class - * - * @param {string} code - W3C Key Code - * @param {number} tDown - time of key press (keydown event) relative to the global Monotonic Clock - * @param {string | undefined} name - pyglet key name + * <pKeyPress holds information about a key that has been pressed, such as the duration of the press.</p> */ export class KeyPress { + /** + * @memberof module:core + * @param {string} code - W3C Key Code + * @param {number} tDown - time of key press (keydown event) relative to the global Monotonic Clock + * @param {string | undefined} name - pyglet key name + */ constructor(code, tDown, name) { this.code = code; @@ -67,18 +92,20 @@ export class KeyPress /** * <p>This manager handles all keyboard events. It is a substitute for the keyboard component of EventManager. </p> * - * @name module:core.Keyboard - * @class - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {number} [options.bufferSize= 10000] - the maximum size of the circular keyboard event buffer - * @param {boolean} [options.waitForStart= false] - whether or not to wait for a call to module:core.Keyboard#start - * before recording keyboard events - * @param {Clock} [options.clock= undefined] - an optional clock - * @param {boolean} [options.autoLog= false] - whether or not to log + * @extends PsychObject */ export class Keyboard extends PsychObject { + /** + * @memberof module:core + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {number} [options.bufferSize= 10000] - the maximum size of the circular keyboard event buffer + * @param {boolean} [options.waitForStart= false] - whether or not to wait for a call to module:core.Keyboard#start + * before recording keyboard events + * @param {Clock} [options.clock= undefined] - an optional clock + * @param {boolean} [options.autoLog= false] - whether or not to log + */ constructor({ psychoJS, bufferSize = 10000, @@ -110,11 +137,6 @@ export class Keyboard extends PsychObject /** * Start recording keyboard events. - * - * @name module:core.Keyboard#start - * @function - * @public - * */ start() { @@ -123,11 +145,6 @@ export class Keyboard extends PsychObject /** * Stop recording keyboard events. - * - * @name module:core.Keyboard#stop - * @function - * @public - * */ stop() { @@ -147,9 +164,6 @@ export class Keyboard extends PsychObject * Get the list of those keyboard events still in the buffer, i.e. those that have not been * previously cleared by calls to getKeys with clear = true. * - * @name module:core.Keyboard#getEvents - * @function - * @public * @return {Keyboard.KeyEvent[]} the list of events still in the buffer */ getEvents() @@ -179,9 +193,6 @@ export class Keyboard extends PsychObject /** * Get the list of keys pressed or pushed by the participant. * - * @name module:core.Keyboard#getKeys - * @function - * @public * @param {Object} options * @param {string[]} [options.keyList= []]] - the list of keys to consider. If keyList is empty, we consider all keys. * Note that we use pyglet keys here, to make the PsychoJs code more homogeneous with PsychoPy. @@ -328,9 +339,6 @@ export class Keyboard extends PsychObject /** * Clear all events and resets the circular buffers. - * - * @name module:core.Keyboard#clearEvents - * @function */ clearEvents() { @@ -347,9 +355,6 @@ export class Keyboard extends PsychObject /** * Test whether a list of KeyPress's contains one with a particular name. * - * @name module:core.Keyboard#includes - * @function - * @static * @param {module:core.KeyPress[]} keypressList - list of KeyPress's * @param {string } keyName - pyglet key name, e.g. 'escape', 'left' * @return {boolean} whether or not a KeyPress with the given pyglet key name is present in the list @@ -368,9 +373,7 @@ export class Keyboard extends PsychObject /** * Add key listeners to the document. * - * @name module:core.Keyboard#_addKeyListeners - * @function - * @private + * @protected */ _addKeyListeners() { @@ -483,10 +486,8 @@ export class Keyboard extends PsychObject /** * Keyboard KeyStatus. * - * @name module:core.Keyboard#KeyStatus * @enum {Symbol} * @readonly - * @public */ Keyboard.KeyStatus = { KEY_DOWN: Symbol.for("KEY_DOWN"), @@ -499,19 +500,23 @@ Keyboard.KeyStatus = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_Logger.js.html b/docs/core_Logger.js.html index a0647e6..e4989fd 100644 --- a/docs/core_Logger.js.html +++ b/docs/core_Logger.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/Logger.js - - - + core/Logger.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/Logger.js

+ + + + +
+ +

core/Logger.js

+ @@ -30,8 +54,8 @@ * Logger * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -46,13 +70,14 @@ import * as util from "../util/Util.js"; * a remote one, etc.</p> * * <p>Note: we use log4javascript for the console logger, and our own for the server logger.</p> - * - * @name module:core.Logger - * @class - * @param {*} threshold - the logging threshold, e.g. log4javascript.Level.ERROR */ export class Logger { + /** + * @memberof module:core + * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance + * @param {*} threshold - the logging threshold, e.g. log4javascript.Level.ERROR + */ constructor(psychoJS, threshold) { this._psychoJS = psychoJS; @@ -97,8 +122,6 @@ export class Logger /** * Change the logging level. * - * @name module:core.Logger#setLevel - * @public * @param {module:core.Logger.ServerLevel} serverLevel - the new logging level */ setLevel(serverLevel) @@ -110,8 +133,6 @@ export class Logger /** * Log a server message at the EXP level. * - * @name module:core.Logger#exp - * @public * @param {string} msg - the message to be logged. * @param {number} [time] - the logging time * @param {object} [obj] - the associated object (e.g. a Trial) @@ -124,8 +145,6 @@ export class Logger /** * Log a server message at the DATA level. * - * @name module:core.Logger#data - * @public * @param {string} msg - the message to be logged. * @param {number} [time] - the logging time * @param {object} [obj] - the associated object (e.g. a Trial) @@ -138,8 +157,6 @@ export class Logger /** * Log a server message. * - * @name module:core.Logger#log - * @public * @param {string} msg - the message to be logged. * @param {module:core.Logger.ServerLevel} level - logging level * @param {number} [time] - the logging time @@ -178,9 +195,7 @@ export class Logger /** * Check whether or not a log messages must be throttled. * - * @name module:core.Logger#_throttle * @protected - * * @param {number} time - the time of the latest log message * @return {boolean} whether or not to log the message */ @@ -256,9 +271,6 @@ export class Logger * * <p>Note: the logs are compressed using Pako's zlib algorithm. * See https://github.com/nodeca/pako for details.</p> - * - * @name module:core.Logger#flush - * @public */ async flush() { @@ -324,8 +336,7 @@ export class Logger /** * Create a custom console layout. * - * @name module:core.Logger#_customConsoleLayout - * @private + * @protected * @return {*} the custom layout */ _customConsoleLayout() @@ -396,7 +407,6 @@ export class Logger /** * Get the integer value associated with a logging level. * - * @name module:core.Logger#_getValue * @protected * @param {module:core.Logger.ServerLevel} level - the logging level * @return {number} - the value associated with the logging level, or 30 is the logging level is unknown. @@ -411,10 +421,8 @@ export class Logger /** * Server logging level. * - * @name module:core.Logger#ServerLevel * @enum {Symbol} * @readonly - * @public * * @note These are similar to PsychoPy's logging levels, as defined in logging.py */ @@ -434,7 +442,6 @@ Logger.ServerLevel = { * * <p>We use those values to determine whether a log is to be sent to the server or not.</p> * - * @name module:core.Logger#_ServerLevelValue * @enum {number} * @readonly * @protected @@ -456,19 +463,23 @@ Logger._ServerLevelValue = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_MinimalStim.js.html b/docs/core_MinimalStim.js.html index 7cacab3..cd401da 100644 --- a/docs/core_MinimalStim.js.html +++ b/docs/core_MinimalStim.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/MinimalStim.js - - - + core/MinimalStim.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/MinimalStim.js

+ + + + +
+ +

core/MinimalStim.js

+ @@ -30,8 +54,8 @@ * Base class for all stimuli. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.0 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -42,17 +66,18 @@ import { PsychoJS } from "./PsychoJS.js"; /** * <p>MinimalStim is the base class for all stimuli.</p> * - * @name module:core.MinimalStim - * @class * @extends PsychObject - * @param {Object} options - * @param {String} options.name - the name used when logging messages from this stimulus - * @param {module:core.Window} options.win - the associated Window - * @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip - * @param {boolean} [options.autoLog= win.autoLog] - whether or not to log */ export class MinimalStim extends PsychObject { + /** + * @memberof module:core + * @param {Object} options + * @param {String} options.name - the name used when logging messages from this stimulus + * @param {module:core.Window} options.win - the associated Window + * @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip + * @param {boolean} [options.autoLog= win.autoLog] - whether to log + */ constructor({ name, win, autoDraw, autoLog } = {}) { super(win._psychoJS, name); @@ -83,11 +108,8 @@ export class MinimalStim extends PsychObject /** * Setter for the autoDraw attribute. * - * @name module:core.MinimalStim#setAutoDraw - * @function - * @public * @param {boolean} autoDraw - the new value - * @param {boolean} [log= false] - whether or not to log + * @param {boolean} [log= false] - whether to log */ setAutoDraw(autoDraw, log = false) { @@ -107,10 +129,6 @@ export class MinimalStim extends PsychObject /** * Draw this stimulus on the next frame draw. - * - * @name module:core.MinimalStim#draw - * @function - * @public */ draw() { @@ -151,10 +169,6 @@ export class MinimalStim extends PsychObject /** * Hide this stimulus on the next frame draw. - * - * @name module:core.MinimalStim#hide - * @function - * @public */ hide() { @@ -178,10 +192,7 @@ export class MinimalStim extends PsychObject /** * Determine whether an object is inside this stimulus. * - * @name module:core.MinimalStim#contains - * @function * @abstract - * @public * @param {Object} object - the object * @param {String} units - the stimulus units */ @@ -197,11 +208,7 @@ export class MinimalStim extends PsychObject /** * Release the PIXI representation, if there is one. * - * @name module:core.MinimalStim#release - * @function - * @public - * - * @param {boolean} [log= false] - whether or not to log + * @param {boolean} [log= false] - whether to log */ release(log = false) { @@ -220,10 +227,8 @@ export class MinimalStim extends PsychObject * * Note: this is an abstract function, which should not be called. * - * @name module:core.MinimalStim#_updateIfNeeded - * @function * @abstract - * @private + * @protected */ _updateIfNeeded() { @@ -241,19 +246,23 @@ export class MinimalStim extends PsychObject + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_Mouse.js.html b/docs/core_Mouse.js.html index ae96891..b5a8362 100644 --- a/docs/core_Mouse.js.html +++ b/docs/core_Mouse.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/Mouse.js - - - + core/Mouse.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/Mouse.js

+ + + + +
+ +

core/Mouse.js

+ @@ -31,8 +55,8 @@ * * @author Alain Pitiot * @author Sotiri Bakagiannis - isPressedIn - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -44,18 +68,17 @@ import { PsychoJS } from "./PsychoJS.js"; * <p>This manager handles the interactions between the experiment's stimuli and the mouse.</p> * <p>Note: the unit of Mouse is that of its associated Window.</p> * - * @name module:core.Mouse - * @class - * @extends PsychObject - * @param {Object} options - * @param {String} options.name - the name used when logging messages from this stimulus - * @param {Window} options.win - the associated Window - * @param {boolean} [options.autoLog= true] - whether or not to log - * * @todo visible is not handled at the moment (mouse is always visible) */ export class Mouse extends PsychObject { + /** + * @memberof module:core + * @param {Object} options + * @param {String} options.name - the name used when logging messages from this stimulus + * @param {Window} options.win - the associated Window + * @param {boolean} [options.autoLog= true] - whether or not to log + */ constructor({ name, win, @@ -82,9 +105,6 @@ export class Mouse extends PsychObject /** * Get the current position of the mouse in mouse/Window units. * - * @name module:core.Mouse#getPos - * @function - * @public * @return {Array.number} the position of the mouse in mouse/Window units */ getPos() @@ -107,9 +127,6 @@ export class Mouse extends PsychObject * Get the position of the mouse relative to that at the last call to getRel * or getPos, in mouse/Window units. * - * @name module:core.Mouse#getRel - * @function - * @public * @return {Array.number} the relation position of the mouse in mouse/Window units. */ getRel() @@ -133,9 +150,6 @@ export class Mouse extends PsychObject * <p>Note: Even though this method returns a [x, y] array, for most wheels/systems y is the only * value that varies.</p> * - * @name module:core.Mouse#getWheelRel - * @function - * @public * @return {Array.number} the mouse scroll wheel travel */ getWheelRel() @@ -155,9 +169,6 @@ export class Mouse extends PsychObject * * <p>Note: clickReset is typically called at stimulus onset. When the participant presses a button, the time elapsed since the clickReset is stored internally and can be accessed any time afterwards with getPressed.</p> * - * @name module:core.Mouse#getPressed - * @function - * @public * @param {boolean} [getTime= false] whether or not to also return timestamps * @return {Array.number | Array.<Array.number>} either an array of size 3 with the status (1 for pressed, 0 for released) of each mouse button [left, center, right], or a tuple with that array and another array of size 3 with the timestamps. */ @@ -178,9 +189,6 @@ export class Mouse extends PsychObject /** * Helper method for checking whether a stimulus has had any button presses within bounds. * - * @name module:core.Mouse#isPressedIn - * @function - * @public * @param {object|module:visual.VisualStim} shape A type of visual stimulus or object having a `contains()` method. * @param {object|number} [buttons] The target button index potentially tucked inside an object. * @param {object} [options] @@ -250,9 +258,6 @@ export class Mouse extends PsychObject * <li>mouseMoved(distance, [x: number, y: number]: artifically set the previous mouse position to the given coordinates and determine whether the mouse moved further than the given distance</li> * </ul></p> * - * @name module:core.Mouse#mouseMoved - * @function - * @public * @param {undefined|number|Array.number} [distance] - the distance to which the mouse movement is compared (see above for a full description) * @param {boolean|String|Array.number} [reset= false] - see above for a full description * @return {boolean} see above for a full description @@ -347,9 +352,6 @@ export class Mouse extends PsychObject /** * Get the amount of time elapsed since the last mouse movement. * - * @name module:core.Mouse#mouseMoveTime - * @function - * @public * @return {number} the time elapsed since the last mouse movement */ mouseMoveTime() @@ -360,9 +362,6 @@ export class Mouse extends PsychObject /** * Reset the clocks associated to the given mouse buttons. * - * @name module:core.Mouse#clickReset - * @function - * @public * @param {Array.number} [buttons= [0,1,2]] the buttons to reset (0: left, 1: center, 2: right) */ clickReset(buttons = [0, 1, 2]) @@ -382,19 +381,23 @@ export class Mouse extends PsychObject + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_PsychoJS.js.html b/docs/core_PsychoJS.js.html index 2078f27..de12cdf 100644 --- a/docs/core_PsychoJS.js.html +++ b/docs/core_PsychoJS.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/PsychoJS.js - - - + core/PsychoJS.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/PsychoJS.js

+ + + + +
+ +

core/PsychoJS.js

+ @@ -31,8 +55,8 @@ * Main component of the PsychoJS library. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -49,18 +73,11 @@ import { Window } from "./Window.js"; import {Shelf} from "../data/Shelf"; /** - * <p>PsychoJS manages the lifecycle of an experiment. It initialises the PsychoJS library and its various components (e.g. the {@link ServerManager}, the {@link EventManager}), and is used by the experiment to schedule the various tasks.</p> - * - * @class - * @param {Object} options - * @param {boolean} [options.debug= true] whether or not to log debug information in the browser console - * @param {boolean} [options.collectIP= false] whether or not to collect the IP information of the participant + * <p>PsychoJS initialises the library and its various components (e.g. the [ServerManager]{@link module:core.ServerManager}, the [EventManager]{@link module:core.EventManager}), and manages + * the lifecycle of an experiment.</p> */ export class PsychoJS { - /** - * Properties - */ get status() { return this._status; @@ -143,8 +160,9 @@ export class PsychoJS } /** - * @constructor - * @public + * @param {Object} options + * @param {boolean} [options.debug= true] whether to log debug information in the browser console + * @param {boolean} [options.collectIP= false] whether to collect the IP information of the participant */ constructor({ debug = true, @@ -204,7 +222,7 @@ export class PsychoJS } this.logger.info("[PsychoJS] Initialised."); - this.logger.info("[PsychoJS] @version 2022.2.0"); + this.logger.info("[PsychoJS] @version 2022.2.1"); // hide the initialisation message: const root = document.getElementById("root"); @@ -240,8 +258,6 @@ export class PsychoJS * @param {boolean} [options.waitBlanking] whether or not to wait for all rendering operations to be done * before flipping * @throws {Object.<string, *>} exception if a window has already been opened - * - * @public */ openWindow({ name, @@ -291,9 +307,8 @@ export class PsychoJS /** * Schedule a task. * - * @param task - the task to be scheduled - * @param args - arguments for that task - * @public + * @param {module:util.Scheduler~Task} task - the task to be scheduled + * @param {*} args - arguments for that task */ schedule(task, args) { @@ -310,9 +325,8 @@ export class PsychoJS * Schedule a series of task based on a condition. * * @param {PsychoJS.condition} condition - * @param {Scheduler} thenScheduler scheduler to run if the condition is true - * @param {Scheduler} elseScheduler scheduler to run if the condition is false - * @public + * @param {Scheduler} thenScheduler - scheduler to run if the condition is true + * @param {Scheduler} elseScheduler - scheduler to run if the condition is false */ scheduleCondition(condition, thenScheduler, elseScheduler) { @@ -340,8 +354,6 @@ export class PsychoJS * @param {string} [options.expName=UNKNOWN] - the name of the experiment * @param {Object.<string, *>} [options.expInfo] - additional information about the experiment * @param {Array.<{name: string, path: string}>} [resources=[]] - the list of resources - * @async - * @public */ async start({ configURL = "config.json", expName = "UNKNOWN", expInfo = {}, resources = [], dataFileName } = {}) { @@ -452,7 +464,6 @@ export class PsychoJS * local to index.html unless they are prepended with a protocol.</li> * * @param {Array.<{name: string, path: string}>} [resources=[]] - the list of resources - * @public */ waitForResources(resources = []) { @@ -476,7 +487,6 @@ export class PsychoJS * Make the attributes of the given object those of window, such that they become global. * * @param {Object.<string, *>} obj the object whose attributes are to become global - * @public */ importAttributes(obj) { @@ -502,9 +512,7 @@ export class PsychoJS * * @param {Object} options * @param {string} [options.message] - optional message to be displayed in a dialog box before quitting - * @param {boolean} [options.isCompleted = false] - whether or not the participant has completed the experiment - * @async - * @public + * @param {boolean} [options.isCompleted = false] - whether the participant has completed the experiment */ async quit({ message, isCompleted = false } = {}) { @@ -512,6 +520,7 @@ export class PsychoJS this._experiment.experimentEnded = true; this._status = PsychoJS.Status.FINISHED; + const isServerEnv = this.getEnvironment() === ExperimentHandler.Environment.SERVER; try { @@ -519,28 +528,32 @@ export class PsychoJS this._scheduler.stop(); // remove the beforeunload listener: - if (this.getEnvironment() === ExperimentHandler.Environment.SERVER) + if (isServerEnv) { window.removeEventListener("beforeunload", this.beforeunloadCallback); } // save the results and the logs of the experiment: - this.gui.dialog({ - warning: "Closing the session. Please wait a few moments.", - showOK: false, + this.gui.finishDialog({ + text: "Terminating the experiment. Please wait a few moments...", + nbSteps: 2 + ((isServerEnv) ? 1 : 0) }); + if (isCompleted || this._config.experiment.saveIncompleteResults) { if (!this._serverMsg.has("__noOutput")) { + this.gui.finishDialogNextStep("saving results"); await this._experiment.save(); + this.gui.finishDialogNextStep("saving logs"); await this._logger.flush(); } } // close the session: - if (this.getEnvironment() === ExperimentHandler.Environment.SERVER) + if (isServerEnv) { + this.gui.finishDialogNextStep("closing the session"); await this._serverManager.closeSession(isCompleted); } @@ -575,6 +588,7 @@ export class PsychoJS } }, }); + } catch (error) { @@ -586,7 +600,6 @@ export class PsychoJS /** * Configure PsychoJS for the running experiment. * - * @async * @protected * @param {string} configURL - the URL of the configuration file * @param {string} name - the name of the experiment @@ -737,7 +750,6 @@ export class PsychoJS /** * Capture all errors and display them in a pop-up error box. - * * @protected */ _captureErrors() @@ -784,7 +796,7 @@ export class PsychoJS /** * Make the various Status top level, in order to accommodate PsychoPy's Code Components. - * @private + * @protected */ _makeStatusTopLevel() { @@ -800,7 +812,6 @@ export class PsychoJS * * @enum {Symbol} * @readonly - * @public * * @note PsychoPy is currently moving away from STOPPED and replacing STOPPED by FINISHED. * For backward compatibility reasons, we are keeping @@ -824,19 +835,23 @@ PsychoJS.Status = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_ServerManager.js.html b/docs/core_ServerManager.js.html index 4350597..916654e 100644 --- a/docs/core_ServerManager.js.html +++ b/docs/core_ServerManager.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/ServerManager.js - - - + core/ServerManager.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/ServerManager.js

+ + + + +
+ +

core/ServerManager.js

+ @@ -30,8 +54,8 @@ * Manager responsible for the communication between the experiment running in the participant's browser and the pavlovia.org server. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -47,25 +71,26 @@ import { PsychoJS } from "./PsychoJS.js"; * <p>This manager handles all communications between the experiment running in the participant's browser and the [pavlovia.org]{@link http://pavlovia.org} server, <em>in an asynchronous manner</em>.</p> * <p>It is responsible for reading the configuration file of an experiment, for opening and closing a session, for listing and downloading resources, and for uploading results, logs, and audio recordings.</p> * - * @name module:core.ServerManager - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {boolean} [options.autoLog= false] - whether or not to log */ export class ServerManager extends PsychObject { - /**************************************************************************** + /** * Used to indicate to the ServerManager that all resources must be registered (and * subsequently downloaded) * - * @type {symbol} + * @type {Symbol} * @readonly * @public */ static ALL_RESOURCES = Symbol.for("ALL_RESOURCES"); + /** + * @memberof module:core + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {boolean} [options.autoLog= false] - whether or not to log + */ constructor({ psychoJS, autoLog = false, @@ -86,21 +111,17 @@ export class ServerManager extends PsychObject this._addAttribute("status", ServerManager.Status.READY); } - /**************************************************************************** + /** * @typedef ServerManager.GetConfigurationPromise * @property {string} origin the calling method * @property {string} context the context * @property {Object.<string, *>} [config] the configuration * @property {Object.<string, *>} [error] an error message if we could not read the configuration file */ - /**************************************************************************** + /** * Read the configuration file for the experiment. * - * @name module:core.ServerManager#getConfiguration - * @function - * @public * @param {string} configURL - the URL of the configuration file - * * @returns {Promise<ServerManager.GetConfigurationPromise>} the response */ getConfiguration(configURL) @@ -147,19 +168,16 @@ export class ServerManager extends PsychObject }); } - /**************************************************************************** + /** * @typedef ServerManager.OpenSessionPromise * @property {string} origin the calling method * @property {string} context the context * @property {string} [token] the session token * @property {Object.<string, *>} [error] an error message if we could not open the session */ - /**************************************************************************** + /** * Open a session for this experiment on the remote PsychoJS manager. * - * @name module:core.ServerManager#openSession - * @function - * @public * @returns {Promise<ServerManager.OpenSessionPromise>} the response */ openSession() @@ -185,24 +203,16 @@ export class ServerManager extends PsychObject { try { - const url = `${this._psychoJS.config.pavlovia.URL}/api/v2/experiments/${this._psychoJS.config.gitlab.projectId}/sessions`; + const postResponse = await this._queryServerAPI( + "POST", + `experiments/${this._psychoJS.config.gitlab.projectId}/sessions`, + data, + "FORM" + ); - const response = await fetch(url, { - method: 'POST', - mode: 'cors', - cache: 'no-cache', - credentials: 'same-origin', - redirect: 'follow', - referrerPolicy: 'no-referrer', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); + const openSessionResponse = await postResponse.json(); - const openSessionResponse = await response.json(); - - if (openSessionResponse.status !== 200) + if (postResponse.status !== 200) { throw ('error' in openSessionResponse) ? openSessionResponse.error : openSessionResponse; } @@ -240,7 +250,6 @@ export class ServerManager extends PsychObject self.setStatus(ServerManager.Status.READY); resolve({...response, token: openSessionResponse.token, status: openSessionResponse.status }); - } catch (error) { @@ -248,71 +257,18 @@ export class ServerManager extends PsychObject self.setStatus(ServerManager.Status.ERROR); reject({...response, error}); } - - /*jQuery.post(url, data, null, "json") - .done((data, textStatus) => - { - if (!("token" in data)) - { - self.setStatus(ServerManager.Status.ERROR); - reject(Object.assign(response, { error: "unexpected answer from server: no token" })); - // reject({...response, error: 'unexpected answer from server: no token'}); - } - if (!("experiment" in data)) - { - self.setStatus(ServerManager.Status.ERROR); - // reject({...response, error: 'unexpected answer from server: no experiment'}); - reject(Object.assign(response, { error: "unexpected answer from server: no experiment" })); - } - - self._psychoJS.config.session = { - token: data.token, - status: "OPEN", - }; - self._psychoJS.config.experiment.status = data.experiment.status2; - self._psychoJS.config.experiment.saveFormat = Symbol.for(data.experiment.saveFormat); - self._psychoJS.config.experiment.saveIncompleteResults = data.experiment.saveIncompleteResults; - self._psychoJS.config.experiment.license = data.experiment.license; - self._psychoJS.config.experiment.runMode = data.experiment.runMode; - - // secret keys for various services, e.g. Google Speech API - if ("keys" in data.experiment) - { - self._psychoJS.config.experiment.keys = data.experiment.keys; - } - else - { - self._psychoJS.config.experiment.keys = []; - } - - self.setStatus(ServerManager.Status.READY); - // resolve({ ...response, token: data.token, status: data.status }); - resolve(Object.assign(response, { token: data.token, status: data.status })); - }) - .fail((jqXHR, textStatus, errorThrown) => - { - self.setStatus(ServerManager.Status.ERROR); - - const errorMsg = util.getRequestError(jqXHR, textStatus, errorThrown); - console.error("error:", errorMsg); - - reject(Object.assign(response, { error: errorMsg })); - });*/ }); } - /**************************************************************************** + /** * @typedef ServerManager.CloseSessionPromise * @property {string} origin the calling method * @property {string} context the context * @property {Object.<string, *>} [error] an error message if we could not close the session (e.g. if it has not previously been opened) */ - /**************************************************************************** + /** * Close the session for this experiment on the remote PsychoJS manager. * - * @name module:core.ServerManager#closeSession - * @function - * @public * @param {boolean} [isCompleted= false] - whether or not the experiment was completed * @param {boolean} [sync= false] - whether or not to communicate with the server in a synchronous manner * @returns {Promise<ServerManager.CloseSessionPromise> | void} the response @@ -323,78 +279,61 @@ export class ServerManager extends PsychObject origin: "ServerManager.closeSession", context: "when closing the session for experiment: " + this._psychoJS.config.experiment.fullpath, }; - this._psychoJS.logger.debug("closing the session for experiment: " + this._psychoJS.config.experiment.name); this.setStatus(ServerManager.Status.BUSY); - // prepare DELETE query: - const url = this._psychoJS.config.pavlovia.URL - + "/api/v2/experiments/" + this._psychoJS.config.gitlab.projectId - + "/sessions/" + this._psychoJS.config.session.token; - - // synchronous query the pavlovia server: + // synchronously query the pavlovia server: if (sync) { - /* This is now deprecated in most browsers. - const request = new XMLHttpRequest(); - request.open("DELETE", url, false); - request.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); - request.send(JSON.stringify(data)); - */ - /* This does not work in Chrome because of a CORS bug - await fetch(url, { - method: 'DELETE', - headers: { 'Content-Type': 'application/json;charset=UTF-8' }, - body: JSON.stringify(data), - // keepalive makes it possible for the request to outlive the page (e.g. when the participant closes the tab) - keepalive: true - }); - */ + const url = this._psychoJS.config.pavlovia.URL + + "/api/v2/experiments/" + this._psychoJS.config.gitlab.projectId + + "/sessions/" + this._psychoJS.config.session.token + "/delete"; const formData = new FormData(); formData.append("isCompleted", isCompleted); - navigator.sendBeacon(url + "/delete", formData); + + navigator.sendBeacon(url, formData); this._psychoJS.config.session.status = "CLOSED"; } // asynchronously query the pavlovia server: else { const self = this; - return new Promise((resolve, reject) => + return new Promise(async (resolve, reject) => { - jQuery.ajax({ - url, - type: "delete", - data: { isCompleted }, - dataType: "json", - }) - .done((data, textStatus) => + try + { + const deleteResponse = await this._queryServerAPI( + "DELETE", + `experiments/${this._psychoJS.config.gitlab.projectId}/sessions/${this._psychoJS.config.session.token}`, + { isCompleted }, + "FORM" + ); + + const closeSessionResponse = await deleteResponse.json(); + + if (deleteResponse.status !== 200) { - self.setStatus(ServerManager.Status.READY); - self._psychoJS.config.session.status = "CLOSED"; + throw ('error' in closeSessionResponse) ? closeSessionResponse.error : closeSessionResponse; + } - // resolve({ ...response, data }); - resolve(Object.assign(response, { data })); - }) - .fail((jqXHR, textStatus, errorThrown) => - { - self.setStatus(ServerManager.Status.ERROR); - - const errorMsg = util.getRequestError(jqXHR, textStatus, errorThrown); - console.error("error:", errorMsg); - - reject(Object.assign(response, { error: errorMsg })); - }); + self.setStatus(ServerManager.Status.READY); + self._psychoJS.config.session.status = "CLOSED"; + resolve({ ...response, ...closeSessionResponse }); + } + catch (error) + { + console.error(error); + self.setStatus(ServerManager.Status.ERROR); + reject({...response, error}); + } }); } } - /**************************************************************************** + /** * Get the value of a resource. * - * @name module:core.ServerManager#getResource - * @function - * @public * @param {string} name - name of the requested resource * @param {boolean} [errorIfNotDownloaded = false] whether or not to throw an exception if the * resource status is not DOWNLOADED @@ -428,7 +367,7 @@ export class ServerManager extends PsychObject return pathStatusData.data; } - /**************************************************************************** + /** * Get the status of a single resource or the reduced status of an array of resources. * * <p>If an array of resources is given, getResourceStatus returns a single, reduced status @@ -443,11 +382,8 @@ export class ServerManager extends PsychObject * </ul> * </p> * - * @name module:core.ServerManager#getResourceStatus - * @function - * @public * @param {string | string[]} names names of the resources whose statuses are requested - * @return {core.ServerManager.ResourceStatus} status of the resource if there is only one, or reduced status otherwise + * @return {module:core.ServerManager.ResourceStatus} status of the resource if there is only one, or reduced status otherwise * @throws {Object.<string, *>} if at least one of the names is not that of a previously * registered resource */ @@ -497,12 +433,8 @@ export class ServerManager extends PsychObject return reducedStatus; } - /**************************************************************************** + /** * Set the resource manager status. - * - * @name module:core.ServerManager#setStatus - * @function - * @public */ setStatus(status) { @@ -530,12 +462,9 @@ export class ServerManager extends PsychObject return this._status; } - /**************************************************************************** + /** * Reset the resource manager status to ServerManager.Status.READY. * - * @name module:core.ServerManager#resetStatus - * @function - * @public * @return {ServerManager.Status.READY} the new status */ resetStatus() @@ -543,7 +472,7 @@ export class ServerManager extends PsychObject return this.setStatus(ServerManager.Status.READY); } - /**************************************************************************** + /** * Prepare resources for the experiment: register them with the server manager and possibly * start downloading them right away. * @@ -556,10 +485,7 @@ export class ServerManager extends PsychObject * <li>If resources is null, then we do not download any resources</li> * </ul> * - * @name module:core.ServerManager#prepareResources * @param {String | Array.<{name: string, path: string, download: boolean} | String | Symbol>} [resources=[]] - the list of resources or a single resource - * @function - * @public */ async prepareResources(resources = []) { @@ -708,13 +634,10 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * Block the experiment until the specified resources have been downloaded. * - * @name module:core.ServerManager#waitForResources * @param {Array.<{name: string, path: string}>} [resources=[]] - the list of resources - * @function - * @public */ waitForResources(resources = []) { @@ -810,22 +733,18 @@ export class ServerManager extends PsychObject }; } - /**************************************************************************** + /** * @typedef ServerManager.UploadDataPromise * @property {string} origin the calling method * @property {string} context the context * @property {Object.<string, *>} [error] an error message if we could not upload the data */ - /**************************************************************************** + /** * Asynchronously upload experiment data to the pavlovia server. * - * @name module:core.ServerManager#uploadData - * @function - * @public * @param {string} key - the data key (e.g. the name of .csv file) * @param {string} value - the data value (e.g. a string containing the .csv header and records) * @param {boolean} [sync= false] - whether or not to communicate with the server in a synchronous manner - * * @returns {Promise<ServerManager.UploadDataPromise>} the response */ uploadData(key, value, sync = false) @@ -834,59 +753,58 @@ export class ServerManager extends PsychObject origin: "ServerManager.uploadData", context: "when uploading participant's results for experiment: " + this._psychoJS.config.experiment.fullpath, }; - this._psychoJS.logger.debug("uploading data for experiment: " + this._psychoJS.config.experiment.fullpath); + this.setStatus(ServerManager.Status.BUSY); - const url = this._psychoJS.config.pavlovia.URL - + "/api/v2/experiments/" + encodeURIComponent(this._psychoJS.config.experiment.fullpath) - + "/sessions/" + this._psychoJS.config.session.token - + "/results"; + const path = `experiments/${this._psychoJS.config.gitlab.projectId}/sessions/${this._psychoJS.config.session.token}/results`; - // synchronous query the pavlovia server: + // synchronously query the pavlovia server: if (sync) { const formData = new FormData(); formData.append("key", key); formData.append("value", value); - navigator.sendBeacon(url, formData); + navigator.sendBeacon(`${this._psychoJS.config.pavlovia.URL}/api/v2/${path}`, formData); } // asynchronously query the pavlovia server: else { const self = this; - return new Promise((resolve, reject) => + return new Promise(async (resolve, reject) => { - const data = { - key, - value, - }; + try + { + const postResponse = await this._queryServerAPI( + "POST", + `experiments/${this._psychoJS.config.gitlab.projectId}/sessions/${this._psychoJS.config.session.token}/results`, + { key, value }, + "FORM" + ); - jQuery.post(url, data, null, "json") - .done((serverData, textStatus) => + const uploadDataResponse = await postResponse.json(); + + if (postResponse.status !== 200) { - self.setStatus(ServerManager.Status.READY); - resolve(Object.assign(response, { serverData })); - }) - .fail((jqXHR, textStatus, errorThrown) => - { - self.setStatus(ServerManager.Status.ERROR); + throw ('error' in uploadDataResponse) ? uploadDataResponse.error : uploadDataResponse; + } - const errorMsg = util.getRequestError(jqXHR, textStatus, errorThrown); - console.error("error:", errorMsg); - - reject(Object.assign(response, { error: errorMsg })); - }); + self.setStatus(ServerManager.Status.READY); + resolve({ ...response, ...uploadDataResponse }); + } + catch (error) + { + console.error(error); + self.setStatus(ServerManager.Status.ERROR); + reject({...response, error}); + } }); } } - /**************************************************************************** + /** * Asynchronously upload experiment logs to the pavlovia server. * - * @name module:core.ServerManager#uploadLog - * @function - * @public * @param {string} logs - the base64 encoded, compressed, formatted logs * @param {boolean} [compressed=false] - whether or not the logs are compressed * @returns {Promise<ServerManager.UploadDataPromise>} the response @@ -897,55 +815,56 @@ export class ServerManager extends PsychObject origin: "ServerManager.uploadLog", context: "when uploading participant's log for experiment: " + this._psychoJS.config.experiment.fullpath, }; - this._psychoJS.logger.debug("uploading server log for experiment: " + this._psychoJS.config.experiment.fullpath); + this.setStatus(ServerManager.Status.BUSY); - // prepare the POST query: + // prepare a POST query: const info = this.psychoJS.experiment.extraInfo; - const participant = ((typeof info.participant === "string" && info.participant.length > 0) ? info.participant : "PARTICIPANT"); - const experimentName = (typeof info.expName !== "undefined") ? info.expName : this.psychoJS.config.experiment.name; - const datetime = ((typeof info.date !== "undefined") ? info.date : MonotonicClock.getDateStr()); - const filename = participant + "_" + experimentName + "_" + datetime + ".log"; + const filenameWithoutPath = this.psychoJS.experiment.dataFileName.split(/[\\/]/).pop(); + const filename = `${filenameWithoutPath}.log`; const data = { filename, logs, - compressed, + compressed }; // query the pavlovia server: const self = this; - return new Promise((resolve, reject) => + return new Promise(async (resolve, reject) => { - const url = self._psychoJS.config.pavlovia.URL - + "/api/v2/experiments/" + encodeURIComponent(self._psychoJS.config.experiment.fullpath) - + "/sessions/" + self._psychoJS.config.session.token - + "/logs"; + try + { + const postResponse = await this._queryServerAPI( + "POST", + `experiments/${this._psychoJS.config.gitlab.projectId}/sessions/${self._psychoJS.config.session.token}/logs`, + data, + "FORM" + ); - jQuery.post(url, data, null, "json") - .done((serverData, textStatus) => + const uploadLogsResponse = await postResponse.json(); + + if (postResponse.status !== 200) { - self.setStatus(ServerManager.Status.READY); - resolve(Object.assign(response, { serverData })); - }) - .fail((jqXHR, textStatus, errorThrown) => - { - self.setStatus(ServerManager.Status.ERROR); + throw ('error' in uploadLogsResponse) ? uploadLogsResponse.error : uploadLogsResponse; + } - const errorMsg = util.getRequestError(jqXHR, textStatus, errorThrown); - console.error("error:", errorMsg); + self.setStatus(ServerManager.Status.READY); + resolve({...response, ...uploadLogsResponse }); + } + catch (error) + { + console.error(error); + self.setStatus(ServerManager.Status.ERROR); + reject({...response, error}); + } - reject(Object.assign(response, { error: errorMsg })); - }); }); } - /**************************************************************************** + /** * Synchronously or asynchronously upload audio data to the pavlovia server. * - * @name module:core.ServerManager#uploadAudioVideo - * @function - * @public * @param @param {Object} options * @param {Blob} options.mediaBlob - the audio or video blob to be uploaded * @param {string} options.tag - additional tag @@ -1075,12 +994,10 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * List the resources available to the experiment. * - * @name module:core.ServerManager#_listResources - * @function - * @private + * @protected */ _listResources() { @@ -1092,61 +1009,53 @@ export class ServerManager extends PsychObject this.setStatus(ServerManager.Status.BUSY); - // prepare GET data: + // prepare a GET query: const data = { "token": this._psychoJS.config.session.token, }; - // query pavlovia server: + // query the server: const self = this; - return new Promise((resolve, reject) => + return new Promise(async (resolve, reject) => { - const url = this._psychoJS.config.pavlovia.URL - + "/api/v2/experiments/" + encodeURIComponent(this._psychoJS.config.experiment.fullpath) - + "/resources"; + try + { + const getResponse = await this._queryServerAPI( + "GET", + `experiments/${this._psychoJS.config.gitlab.projectId}/resources`, + data + ); - jQuery.get(url, data, null, "json") - .done((data, textStatus) => - { - if (!("resources" in data)) - { - self.setStatus(ServerManager.Status.ERROR); - // reject({ ...response, error: 'unexpected answer from server: no resources' }); - reject(Object.assign(response, { error: "unexpected answer from server: no resources" })); - } - if (!("resourceDirectory" in data)) - { - self.setStatus(ServerManager.Status.ERROR); - // reject({ ...response, error: 'unexpected answer from server: no resourceDirectory' }); - reject(Object.assign(response, { error: "unexpected answer from server: no resourceDirectory" })); - } + const getResourcesResponse = await getResponse.json(); - self.setStatus(ServerManager.Status.READY); - // resolve({ ...response, resources: data.resources, resourceDirectory: data.resourceDirectory }); - resolve(Object.assign(response, { - resources: data.resources, - resourceDirectory: data.resourceDirectory, - })); - }) - .fail((jqXHR, textStatus, errorThrown) => + if (!("resources" in getResourcesResponse)) { self.setStatus(ServerManager.Status.ERROR); + throw "unexpected answer from server: no resources"; + } + if (!("resourceDirectory" in getResourcesResponse)) + { + self.setStatus(ServerManager.Status.ERROR); + throw "unexpected answer from server: no resourceDirectory"; + } - const errorMsg = util.getRequestError(jqXHR, textStatus, errorThrown); - console.error("error:", errorMsg); - - reject(Object.assign(response, { error: errorMsg })); - }); + self.setStatus(ServerManager.Status.READY); + resolve({ ...response, resources: data.resources, resourceDirectory: data.resourceDirectory }); + } + catch (error) + { + console.error(error); + self.setStatus(ServerManager.Status.ERROR); + reject({...response, error}); + } }); } - /**************************************************************************** + /** * Download the specified resources. * * <p>Note: we use the [preloadjs library]{@link https://www.createjs.com/preloadjs}.</p> * - * @name module:core.ServerManager#_downloadResources - * @function * @protected * @param {Set} resources - a set of names of previously registered resources */ @@ -1344,11 +1253,9 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * Setup the preload.js queue, and the associated callbacks. * - * @name module:core.ServerManager#_setupPreloadQueue - * @function * @protected */ _setupPreloadQueue() @@ -1436,18 +1343,87 @@ export class ServerManager extends PsychObject }); } + /** + * Query the pavlovia server API. + * + * @protected + * @param method the HTTP method, i.e. GET, PUT, POST, or DELETE + * @param path the resource path, without the server address + * @param data the data to be sent + * @param {string} [contentType="JSON"] the content type, either JSON or FORM + */ + _queryServerAPI(method, path, data, contentType = "JSON") + { + const fullPath = `${this._psychoJS.config.pavlovia.URL}/api/v2/${path}`; + + if (method === "PUT" || method === "POST" || method === "DELETE") + { + if (contentType === "JSON") + { + return fetch(fullPath, { + method, + mode: 'cors', + cache: 'no-cache', + credentials: 'same-origin', + redirect: 'follow', + referrerPolicy: 'no-referrer', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + } + else + { + const formData = new FormData(); + for (const attribute in data) + { + formData.append(attribute, data[attribute]); + } + + return fetch(fullPath, { + method, + mode: 'cors', + cache: 'no-cache', + credentials: 'same-origin', + redirect: 'follow', + referrerPolicy: 'no-referrer', + body: formData + }); + } + } + + if (method === "GET") + { + let url = new URL(fullPath); + url.search = new URLSearchParams(data).toString(); + + return fetch(url, { + method: "GET", + mode: "cors", + cache: "no-cache", + credentials: "same-origin", + redirect: "follow", + referrerPolicy: "no-referrer" + }); + } + + throw { + origin: "ServerManager._queryServer", + context: "when querying the server", + error: "the method should be GET, PUT, POST, or DELETE" + }; + } } -/**************************************************************************** +/** * Server event * * <p>A server event is emitted by the manager to inform its listeners of either a change of status, or of a resource related event (e.g. download started, download is completed).</p> * - * @name module:core.ServerManager#Event * @enum {Symbol} * @readonly - * @public */ ServerManager.Event = { /** @@ -1473,7 +1449,7 @@ ServerManager.Event = { /** * Event: resources have all downloaded */ - DOWNLOADS_COMPLETED: Symbol.for("DOWNLOAD_COMPLETED"), + DOWNLOAD_COMPLETED: Symbol.for("DOWNLOAD_COMPLETED"), /** * Event type: status event @@ -1481,13 +1457,11 @@ ServerManager.Event = { STATUS: Symbol.for("STATUS"), }; -/**************************************************************************** +/** * Server status * - * @name module:core.ServerManager#Status * @enum {Symbol} * @readonly - * @public */ ServerManager.Status = { /** @@ -1506,13 +1480,11 @@ ServerManager.Status = { ERROR: Symbol.for("ERROR"), }; -/**************************************************************************** +/** * Resource status * - * @name module:core.ServerManager#ResourceStatus * @enum {Symbol} * @readonly - * @public */ ServerManager.ResourceStatus = { /** @@ -1542,19 +1514,23 @@ ServerManager.ResourceStatus = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_Window.js.html b/docs/core_Window.js.html index b00a7ef..267b4a4 100644 --- a/docs/core_Window.js.html +++ b/docs/core_Window.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/Window.js - - - + core/Window.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/Window.js

+ + + + +
+ +

core/Window.js

+ @@ -30,8 +54,8 @@ * Window responsible for displaying the experiment stimuli * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -46,20 +70,7 @@ import { Logger } from "./Logger.js"; * <p>Window displays the various stimuli of the experiment.</p> * <p>It sets up a [PIXI]{@link http://www.pixijs.com/} renderer, which we use to render the experiment stimuli.</p> * - * @name module:core.Window - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} [options.name] the name of the window - * @param {boolean} [options.fullscr= false] whether or not to go fullscreen - * @param {Color} [options.color= Color('black')] the background color of the window - * @param {number} [options.gamma= 1] sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma) - * @param {number} [options.contrast= 1] sets the contrast value - * @param {string} [options.units= 'pix'] the units of the window - * @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done - * before flipping - * @param {boolean} [options.autoLog= true] whether or not to log */ export class Window extends PsychObject { @@ -75,6 +86,20 @@ export class Window extends PsychObject return 1.0 / this.getActualFrameRate(); } + /** + * @memberof module:core + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} [options.name] the name of the window + * @param {boolean} [options.fullscr= false] whether or not to go fullscreen + * @param {Color} [options.color= Color('black')] the background color of the window + * @param {number} [options.gamma= 1] sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma) + * @param {number} [options.contrast= 1] sets the contrast value + * @param {string} [options.units= 'pix'] the units of the window + * @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done + * before flipping + * @param {boolean} [options.autoLog= true] whether or not to log + */ constructor({ psychoJS, name, @@ -104,7 +129,7 @@ export class Window extends PsychObject this._addAttribute("fullscr", fullscr); this._addAttribute("color", color, new Color("black"), () => { if (this._backgroundSprite) { - this._backgroundSprite.tint = color.int; + this._backgroundSprite.tint = this._color.int; } }); this._addAttribute("gamma", gamma, 1, () => { @@ -152,10 +177,6 @@ export class Window extends PsychObject * Close the window. * * <p> Note: this actually only removes the canvas used to render the experiment stimuli.</p> - * - * @name module:core.Window#close - * @function - * @public */ close() { @@ -189,9 +210,6 @@ export class Window extends PsychObject /** * Estimate the frame rate. * - * @name module:core.Window#getActualFrameRate - * @function - * @public * @return {number} rAF based delta time based approximation, 60.0 by default */ getActualFrameRate() @@ -205,10 +223,6 @@ export class Window extends PsychObject /** * Take the browser full screen if possible. - * - * @name module:core.Window#adjustScreenSize - * @function - * @public */ adjustScreenSize() { @@ -250,10 +264,6 @@ export class Window extends PsychObject /** * Take the browser back from full screen if needed. - * - * @name module:core.Window#closeFullScreen - * @function - * @public */ closeFullScreen() { @@ -293,9 +303,6 @@ export class Window extends PsychObject * * <p> Note: the message will be time-stamped at the next call to requestAnimationFrame.</p> * - * @name module:core.Window#logOnFlip - * @function - * @public * @param {Object} options * @param {String} options.msg the message to be logged * @param {module:util.Logger.ServerLevel} [level = module:util.Logger.ServerLevel.EXP] the log level @@ -322,9 +329,6 @@ export class Window extends PsychObject * * <p>This is typically used to reset a timer or clock.</p> * - * @name module:core.Window#callOnFlip - * @function - * @public * @param {module:core.Window~OnFlipCallback} flipCallback - callback function. * @param {...*} flipCallbackArgs - arguments for the callback function. */ @@ -335,10 +339,6 @@ export class Window extends PsychObject /** * Add PIXI.DisplayObject to the container displayed on the scene (window) - * - * @name module:core.Window#addPixiObject - * @function - * @public */ addPixiObject(pixiObject) { @@ -347,10 +347,6 @@ export class Window extends PsychObject /** * Remove PIXI.DisplayObject from the container displayed on the scene (window) - * - * @name module:core.Window#removePixiObject - * @function - * @public */ removePixiObject(pixiObject) { @@ -359,10 +355,6 @@ export class Window extends PsychObject /** * Render the stimuli onto the canvas. - * - * @name module:core.Window#render - * @function - * @public */ render() { @@ -406,9 +398,7 @@ export class Window extends PsychObject /** * Update this window, if need be. * - * @name module:core.Window#_updateIfNeeded - * @function - * @private + * @protected */ _updateIfNeeded() { @@ -417,6 +407,7 @@ export class Window extends PsychObject if (this._renderer) { this._renderer.backgroundColor = this._color.int; + this._backgroundSprite.tint = this._color.int; } // we also change the background color of the body since @@ -430,9 +421,7 @@ export class Window extends PsychObject /** * Recompute this window's draw list and _container children for the next animation frame. * - * @name module:core.Window#_refresh - * @function - * @private + * @protected */ _refresh() { @@ -454,9 +443,7 @@ export class Window extends PsychObject /** * Force an update of all stimuli in this window's drawlist. * - * @name module:core.Window#_fullRefresh - * @function - * @private + * @protected */ _fullRefresh() { @@ -476,9 +463,7 @@ export class Window extends PsychObject * <p>A new renderer is created and a container is added to it. The renderer's touch and mouse events * are handled by the {@link EventManager}.</p> * - * @name module:core.Window#_setupPixi - * @function - * @private + * @protected */ _setupPixi() { @@ -538,6 +523,8 @@ export class Window extends PsychObject this._resizeCallback = (e) => { Window._resizePixiRenderer(this, e); + this._backgroundSprite.width = this._size[0]; + this._backgroundSprite.height = this._size[1]; this._fullRefresh(); }; window.addEventListener("resize", this._resizeCallback); @@ -548,9 +535,7 @@ export class Window extends PsychObject * Adjust the size of the renderer and the position of the root container * in response to a change in the browser's size. * - * @name module:core.Window#_resizePixiRenderer - * @function - * @private + * @protected * @param {module:core.Window} pjsWindow - the PsychoJS Window * @param event */ @@ -579,9 +564,7 @@ export class Window extends PsychObject /** * Send all logged messages to the {@link Logger}. * - * @name module:core.Window#_writeLogOnFlip - * @function - * @private + * @protected */ _writeLogOnFlip() { @@ -601,19 +584,23 @@ export class Window extends PsychObject + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/core_WindowMixin.js.html b/docs/core_WindowMixin.js.html index 11de007..047687f 100644 --- a/docs/core_WindowMixin.js.html +++ b/docs/core_WindowMixin.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: core/WindowMixin.js - - - + core/WindowMixin.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: core/WindowMixin.js

+ + + + +
+ +

core/WindowMixin.js

+ @@ -30,8 +54,8 @@ * Mixin implementing various unit-handling measurement methods. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -221,19 +245,23 @@ export let WindowMixin = (superclass) => + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/data_ExperimentHandler.js.html b/docs/data_ExperimentHandler.js.html index 9ee6b40..6a59258 100644 --- a/docs/data_ExperimentHandler.js.html +++ b/docs/data_ExperimentHandler.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: data/ExperimentHandler.js - - - + data/ExperimentHandler.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: data/ExperimentHandler.js

+ + + + +
+ +

data/ExperimentHandler.js

+ @@ -30,8 +54,8 @@ * Experiment Handler * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -45,22 +69,12 @@ import * as util from "../util/Util.js"; * for generating a single data file from an experiment with many different loops (e.g. interleaved * staircases or loops within loops.</p> * - * @name module:data.ExperimentHandler - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} options.name - name of the experiment - * @param {Object} options.extraInfo - additional information, such as session name, participant name, etc. */ export class ExperimentHandler extends PsychObject { /** * Getter for experimentEnded. - * - * @name module:data.ExperimentHandler#experimentEnded - * @function - * @public */ get experimentEnded() { @@ -69,10 +83,6 @@ export class ExperimentHandler extends PsychObject /** * Setter for experimentEnded. - * - * @name module:data.ExperimentHandler#experimentEnded - * @function - * @public */ set experimentEnded(ended) { @@ -92,6 +102,13 @@ export class ExperimentHandler extends PsychObject return this._trialsData; } + /** + * @memberof module:data + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} options.name - name of the experiment + * @param {Object} options.extraInfo - additional information, such as session name, participant name, etc. + */ constructor({ psychoJS, name, @@ -139,9 +156,6 @@ export class ExperimentHandler extends PsychObject * Whether or not the current entry (i.e. trial data) is empty. * <p>Note: this is mostly useful at the end of an experiment, in order to ensure that the last entry is saved.</p> * - * @name module:data.ExperimentHandler#isEntryEmpty - * @function - * @public * @returns {boolean} whether or not the current entry is empty * @todo This really should be renamed: IsCurrentEntryNotEmpty */ @@ -156,9 +170,6 @@ export class ExperimentHandler extends PsychObject * <p> The loop might be a {@link TrialHandler}, for instance.</p> * <p> Data from this loop will be included in the resulting data files.</p> * - * @name module:data.ExperimentHandler#addLoop - * @function - * @public * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler */ addLoop(loop) @@ -171,9 +182,6 @@ export class ExperimentHandler extends PsychObject /** * Remove the given loop from the list of unfinished loops, e.g. when it has completed. * - * @name module:data.ExperimentHandler#removeLoop - * @function - * @public * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler */ removeLoop(loop) @@ -191,9 +199,6 @@ export class ExperimentHandler extends PsychObject * <p> Multiple key/value pairs can be added to any given entry of the data file. There are * considered part of the same entry until a call to {@link nextEntry} is made. </p> * - * @name module:data.ExperimentHandler#addData - * @function - * @public * @param {Object} key - the key * @param {Object} value - the value */ @@ -217,9 +222,6 @@ export class ExperimentHandler extends PsychObject * Inform this ExperimentHandler that the current trial has ended. Further calls to {@link addData} * will be associated with the next trial. * - * @name module:data.ExperimentHandler#nextEntry - * @function - * @public * @param {Object | Object[] | undefined} snapshots - array of loop snapshots */ nextEntry(snapshots) @@ -284,9 +286,6 @@ export class ExperimentHandler extends PsychObject * </ul> * <p> * - * @name module:data.ExperimentHandler#save - * @function - * @public * @param {Object} options * @param {Array.<Object>} [options.attributes] - the attributes to be saved * @param {boolean} [options.sync=false] - whether or not to communicate with the server in a synchronous manner @@ -408,9 +407,6 @@ export class ExperimentHandler extends PsychObject * Get the attribute names and values for the current trial of a given loop. * <p> Only info relating to the trial execution are returned.</p> * - * @name module:data.ExperimentHandler#_getLoopAttributes - * @function - * @static * @protected * @param {Object} loop - the loop */ @@ -470,10 +466,8 @@ export class ExperimentHandler extends PsychObject /** * Experiment result format * - * @name module:core.ServerManager#SaveFormat * @enum {Symbol} * @readonly - * @public */ ExperimentHandler.SaveFormat = { /** @@ -492,7 +486,6 @@ ExperimentHandler.SaveFormat = { * * @enum {Symbol} * @readonly - * @public */ ExperimentHandler.Environment = { SERVER: Symbol.for("SERVER"), @@ -505,19 +498,23 @@ ExperimentHandler.Environment = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/data_MultiStairHandler.js.html b/docs/data_MultiStairHandler.js.html index 6d5b8d7..f77f3b8 100644 --- a/docs/data_MultiStairHandler.js.html +++ b/docs/data_MultiStairHandler.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: data/MultiStairHandler.js - - - + data/MultiStairHandler.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: data/MultiStairHandler.js

+ + + + +
+ +

data/MultiStairHandler.js

+ @@ -26,13 +50,12 @@
-
/** @module data */
-/**
+            
/**
  * Multiple Staircase Trial Handler
  *
  * @author Alain Pitiot
- * @version 2021.2.1
- * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd.
+ * @version 2021.2.3
+ * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd.
  *   (https://opensciencetools.org)
  * @license Distributed under the terms of the MIT License
  */
@@ -50,27 +73,25 @@ import seedrandom from "seedrandom";
  * <p>Note that, at the moment, using the MultiStairHandler requires the jsQuest.js
  * library to be loaded as a resource, at the start of the experiment.</p>
  *
- * @class module.data.MultiStairHandler
  * @extends TrialHandler
- * @param {Object} options - the handler options
- * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
- * @param {string} options.varName - the name of the variable / intensity / contrast
- * 	/ threshold manipulated by the staircases
- * @param {module:data.MultiStairHandler.StaircaseType} [options.stairType="simple"] - the
- * 	handler type
- * @param {Array.<Object> | String} [options.conditions= [undefined] ] - if it is a string,
- * 	we treat it as the name of a conditions resource
- * @param {module:data.TrialHandler.Method} options.method - the trial method
- * @param {number} [options.nTrials=50] - maximum number of trials
- * @param {number} options.randomSeed - seed for the random number generator
- * @param {string} options.name - name of the handler
- * @param {boolean} [options.autoLog= false] - whether or not to log
  */
 export class MultiStairHandler extends TrialHandler
 {
 	/**
-	 * @constructor
-	 * @public
+	 * @memberof module:data
+	 * @param {Object} options - the handler options
+	 * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
+	 * @param {string} options.varName - the name of the variable / intensity / contrast
+	 * 	/ threshold manipulated by the staircases
+	 * @param {MultiStairHandler.StaircaseType} [options.stairType="simple"] - the
+	 * 	handler type
+	 * @param {Array.<Object> | String} [options.conditions= [undefined] ] - if it is a string,
+	 * 	we treat it as the name of a conditions resource
+	 * @param {module:data.TrialHandler.Method} options.method - the trial method
+	 * @param {number} [options.nTrials=50] - maximum number of trials
+	 * @param {number} options.randomSeed - seed for the random number generator
+	 * @param {string} options.name - name of the handler
+	 * @param {boolean} [options.autoLog= false] - whether or not to log
 	 */
 	constructor({
 		psychoJS,
@@ -119,10 +140,7 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Get the current staircase.
 	 *
-	 * @name module:data.MultiStairHandler#currentStaircase
-	 * @function
-	 * @public
-	 * @returns {module.data.TrialHandler} the current staircase, or undefined if the trial has ended
+	 * @returns {TrialHandler} the current staircase, or undefined if the trial has ended
 	 */
 	get currentStaircase()
 	{
@@ -132,9 +150,6 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Get the current intensity.
 	 *
-	 * @name module:data.MultiStairHandler#intensity
-	 * @function
-	 * @public
 	 * @returns {number} the intensity of the current staircase, or undefined if the trial has ended
 	 */
 	get intensity()
@@ -156,13 +171,9 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Add a response to the current staircase.
 	 *
-	 * @name module:data.MultiStairHandler#addResponse
-	 * @function
-	 * @public
 	 * @param{number} response - the response to the trial, must be either 0 (incorrect or
 	 * non-detected) or 1 (correct or detected)
 	 * @param{number | undefined} [value] - optional intensity / contrast / threshold
-	 * @returns {void}
 	 */
 	addResponse(response, value)
 	{
@@ -191,10 +202,7 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Validate the conditions.
 	 *
-	 * @name module:data.MultiStairHandler#_validateConditions
-	 * @function
 	 * @protected
-	 * @returns {void}
 	 */
 	_validateConditions()
 	{
@@ -250,10 +258,7 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Setup the staircases, according to the conditions.
 	 *
-	 * @name module:data.MultiStairHandler#_prepareStaircases
-	 * @function
 	 * @protected
-	 * @returns {void}
 	 */
 	_prepareStaircases()
 	{
@@ -310,10 +315,7 @@ export class MultiStairHandler extends TrialHandler
 	/**
 	 * Move onto the next trial.
 	 *
-	 * @name module:data.MultiStairHandler#_nextTrial
-	 * @function
 	 * @protected
-	 * @returns {void}
 	 */
 	_nextTrial()
 	{
@@ -453,7 +455,6 @@ export class MultiStairHandler extends TrialHandler
  *
  * @enum {Symbol}
  * @readonly
- * @public
  */
 MultiStairHandler.StaircaseType = {
 	/**
@@ -472,7 +473,6 @@ MultiStairHandler.StaircaseType = {
  *
  * @enum {Symbol}
  * @readonly
- * @public
  */
 MultiStairHandler.StaircaseStatus = {
 	/**
@@ -492,19 +492,23 @@ MultiStairHandler.StaircaseStatus = {
 
 
 
+    
+    
 
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/data_QuestHandler.js.html b/docs/data_QuestHandler.js.html index 878d5a9..56a736f 100644 --- a/docs/data_QuestHandler.js.html +++ b/docs/data_QuestHandler.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: data/QuestHandler.js - - - + data/QuestHandler.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: data/QuestHandler.js

+ + + + +
+ +

data/QuestHandler.js

+ @@ -26,13 +50,12 @@
-
/** @module data */
-/**
+            
/**
  * Quest Trial Handler
  *
  * @author Alain Pitiot & Thomas Pronk
- * @version 2021.2.0
- * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)
+ * @version 2022.2.3
+ * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org)
  * @license Distributed under the terms of the MIT License
  */
 
@@ -43,31 +66,29 @@ import {TrialHandler} from "./TrialHandler.js";
  * <p>A Trial Handler that implements the Quest algorithm for quick measurement of
     psychophysical thresholds. QuestHandler relies on the [jsQuest]{@link https://github.com/kurokida/jsQUEST} library, a port of Prof Dennis Pelli's QUEST algorithm by [Daiichiro Kuroki]{@link https://github.com/kurokida}.</p>
  *
- * @class module.data.QuestHandler
  * @extends TrialHandler
- * @param {Object} options - the handler options
- * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
- * @param {string} options.varName - the name of the variable / intensity / contrast / threshold manipulated by QUEST
- * @param {number} options.startVal - initial guess for the threshold
- * @param {number} options.startValSd - standard deviation of the initial guess
- * @param {number} options.minVal - minimum value for the threshold
- * @param {number} options.maxVal - maximum value for the threshold
- * @param {number} [options.pThreshold=0.82] - threshold criterion expressed as probability of getting a correct response
- * @param {number} options.nTrials - maximum number of trials
- * @param {number} options.stopInterval - minimum [5%, 95%] confidence interval required for the loop to stop
- * @param {module:data.QuestHandler.Method} options.method - the QUEST method
- * @param {number} [options.beta=3.5] - steepness of the QUEST psychometric function
- * @param {number} [options.delta=0.01] - fraction of trials with blind responses
- * @param {number} [options.gamma=0.5] - fraction of trails that would generate a correct response when the threshold is infinitely small
- * @param {number} [options.grain=0.01] - quantization of the internal table
- * @param {string} options.name - name of the handler
- * @param {boolean} [options.autoLog= false] - whether or not to log
  */
 export class QuestHandler extends TrialHandler
 {
 	/**
-	 * @constructor
-	 * @public
+	 * @memberof module:data
+	 * @param {Object} options - the handler options
+	 * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
+	 * @param {string} options.varName - the name of the variable / intensity / contrast / threshold manipulated by QUEST
+	 * @param {number} options.startVal - initial guess for the threshold
+	 * @param {number} options.startValSd - standard deviation of the initial guess
+	 * @param {number} options.minVal - minimum value for the threshold
+	 * @param {number} options.maxVal - maximum value for the threshold
+	 * @param {number} [options.pThreshold=0.82] - threshold criterion expressed as probability of getting a correct response
+	 * @param {number} options.nTrials - maximum number of trials
+	 * @param {number} options.stopInterval - minimum [5%, 95%] confidence interval required for the loop to stop
+	 * @param {QuestHandler.Method} options.method - the QUEST method
+	 * @param {number} [options.beta=3.5] - steepness of the QUEST psychometric function
+	 * @param {number} [options.delta=0.01] - fraction of trials with blind responses
+	 * @param {number} [options.gamma=0.5] - fraction of trails that would generate a correct response when the threshold is infinitely small
+	 * @param {number} [options.grain=0.01] - quantization of the internal table
+	 * @param {string} options.name - name of the handler
+	 * @param {boolean} [options.autoLog= false] - whether or not to log
 	 */
 	constructor({
 		psychoJS,
@@ -141,15 +162,11 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Add a response and update the PDF.
 	 *
-	 * @name module:data.QuestHandler#addResponse
-	 * @function
-	 * @public
 	 * @param{number} response	- the response to the trial, must be either 0 (incorrect or
 	 * non-detected) or 1 (correct or detected)
 	 * @param{number | undefined} value - optional intensity / contrast / threshold
 	 * @param{boolean} [doAddData = true] - whether or not to add the response as data to the
 	 * 	experiment
-	 * @returns {void}
 	 */
 	addResponse(response, value, doAddData = true)
 	{
@@ -191,9 +208,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Simulate a response.
 	 *
-	 * @name module:data.QuestHandler#simulate
-	 * @function
-	 * @public
 	 * @param{number} trueValue - the true, known value of the threshold / contrast / intensity
 	 * @returns{number} the simulated response, 0 or 1
 	 */
@@ -212,9 +226,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get the mean of the Quest posterior PDF.
 	 *
-	 * @name module:data.QuestHandler#mean
-	 * @function
-	 * @public
 	 * @returns {number} the mean
 	 */
 	mean()
@@ -225,9 +236,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get the standard deviation of the Quest posterior PDF.
 	 *
-	 * @name module:data.QuestHandler#sd
-	 * @function
-	 * @public
 	 * @returns {number} the standard deviation
 	 */
 	sd()
@@ -238,9 +246,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get the mode of the Quest posterior PDF.
 	 *
-	 * @name module:data.QuestHandler#mode
-	 * @function
-	 * @public
 	 * @returns {number} the mode
 	 */
 	mode()
@@ -252,9 +257,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get the standard deviation of the Quest posterior PDF.
 	 *
-	 * @name module:data.QuestHandler#quantile
-	 * @function
-	 * @public
 	 * @param{number} quantileOrder the quantile order
 	 * @returns {number} the quantile
 	 */
@@ -266,9 +268,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get the current value of the variable / contrast / threshold.
 	 *
-	 * @name module:data.QuestHandler#getQuestValue
-	 * @function
-	 * @public
 	 * @returns {number} the current QUEST value for the variable / contrast / threshold
 	 */
 	getQuestValue()
@@ -281,9 +280,6 @@ export class QuestHandler extends TrialHandler
 	 *
 	 * <p>This is the getter associated to getQuestValue.</p>
 	 *
-	 * @name module:data.MultiStairHandler#intensity
-	 * @function
-	 * @public
 	 * @returns {number} the intensity of the current staircase, or undefined if the trial has ended
 	 */
 	get intensity()
@@ -294,9 +290,6 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Get an estimate of the 5%-95% confidence interval (CI).
 	 *
-	 * @name module:data.QuestHandler#confInterval
-	 * @function
-	 * @public
 	 * @param{boolean} [getDifference=false] - if true, return the width of the CI instead of the CI
 	 * @returns{number[] | number} the 5%-95% CI or the width of the CI
 	 */
@@ -320,10 +313,7 @@ export class QuestHandler extends TrialHandler
 	/**
 	 * Setup the JS Quest object.
 	 *
-	 * @name module:data.QuestHandler#_setupJsQuest
-	 * @function
 	 * @protected
-	 * @returns {void}
 	 */
 	_setupJsQuest()
 	{
@@ -341,10 +331,7 @@ export class QuestHandler extends TrialHandler
 	 * Estimate the next value of the QUEST variable, based on the current value
 	 * and on the selected QUEST method.
 	 *
-	 * @name module:data.QuestHandler#_estimateQuestValue
-	 * @function
 	 * @protected
-	 * @returns {void}
 	 */
 	_estimateQuestValue()
 	{
@@ -415,7 +402,6 @@ export class QuestHandler extends TrialHandler
  *
  * @enum {Symbol}
  * @readonly
- * @public
  */
 QuestHandler.Method = {
 	/**
@@ -440,19 +426,23 @@ QuestHandler.Method = {
 
 
 
+    
+    
 
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/data_Shelf.js.html b/docs/data_Shelf.js.html index 09e6c3e..0d58bac 100644 --- a/docs/data_Shelf.js.html +++ b/docs/data_Shelf.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: data/Shelf.js - - - + data/Shelf.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: data/Shelf.js

+ + + + +
+ +

data/Shelf.js

+ @@ -26,12 +50,12 @@
-
/** @module data */
-/**
+            
/**
  * Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the
- * server, and be accessed and manipulated in a concurrent fashion.
+ * server, and can be accessed and manipulated in a concurrent fashion.
  *
  * @author Alain Pitiot
+ * @version 2021.2.3
  * @copyright (c) 2022 Open Science Tools Ltd. (https://opensciencetools.org)
  * @license Distributed under the terms of the MIT License
  */
@@ -44,27 +68,25 @@ import {Scheduler} from "../util/Scheduler.js";
 
 /**
  * <p>Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the
- * server, and be accessed and manipulated in a concurrent fashion.</p>
+ * server, and can be accessed and manipulated in a concurrent fashion.</p>
  *
- * <p></p>
- *
- * @name module:data.Shelf
- * @class
  * @extends PsychObject
- * @param {Object} options
- * @param {module:core.PsychoJS} options.psychoJS 	the PsychoJS instance
- * @param {boolean} [options.autoLog= false] 				whether to log
  */
 export class Shelf extends PsychObject
 {
 	/**
 	 * Maximum number of components in a key
-	 * @name module:data.Shelf.#MAX_KEY_LENGTH
 	 * @type {number}
 	 * @note this value should mirror that on the server, i.e. the server also checks that the key is valid
 	 */
 	static #MAX_KEY_LENGTH = 10;
 
+	/**
+	 * @memberOf module:data
+	 * @param {Object} options
+	 * @param {module:core.PsychoJS} options.psychoJS 	the PsychoJS instance
+	 * @param {boolean} [options.autoLog= false] 				whether to log
+	 */
 	constructor({psychoJS, autoLog = false } = {})
 	{
 		super(psychoJS);
@@ -84,9 +106,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a record of type BOOLEAN associated with the given key.
 	 *
-	 * @name module:data.Shelf#getBooleanValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key					 	key as an array of key components
 	 * @param {boolean} options.defaultValue		the default value returned if no record with the given key exists
@@ -103,9 +122,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set the value of a record of type BOOLEAN associated with the given key.
 	 *
-	 * @name module:data.Shelf#setBooleanValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 	key as an array of key components
 	 * @param {boolean} options.value 		the new value
@@ -136,9 +152,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Flip the value of a record of type BOOLEAN associated with the given key.
 	 *
-	 * @name module:data.Shelf#flipBooleanValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @return {Promise<boolean>}				the new, flipped, value
@@ -157,9 +170,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a record of type INTEGER associated with the given key.
 	 *
-	 * @name module:data.Shelf#getIntegerValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 			key as an array of key components
 	 * @param {number} options.defaultValue		the default value returned if no record with the given key
@@ -176,9 +186,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set the value of a record of type INTEGER associated with the given key.
 	 *
-	 * @name module:data.Shelf#setIntegerValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @param {number} options.value 		the new value
@@ -209,9 +216,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Add a delta to  the value of a record of type INTEGER associated with the given key.
 	 *
-	 * @name module:data.Shelf#addIntegerValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 	key as an array of key components
 	 * @param {number} options.delta 		the delta, positive or negative, to add to the value
@@ -242,9 +246,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a record of type TEXT associated with the given key.
 	 *
-	 * @name module:data.Shelf#getTextValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key					 	key as an array of key components
 	 * @param {string} options.defaultValue		the default value returned if no record with the given key exists on
@@ -261,9 +262,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set the value of a record of type TEXT associated with the given key.
 	 *
-	 * @name module:data.Shelf#setTextValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 	key as an array of key components
 	 * @param {string} options.value 			the new value
@@ -294,9 +292,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a record of type LIST associated with the given key.
 	 *
-	 * @name module:data.Shelf#getListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key					 			key as an array of key components
 	 * @param {Array.<*>} options.defaultValue		the default value returned if no record with the given key exists on
@@ -313,9 +308,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set the value of a record of type LIST associated with the given key.
 	 *
-	 * @name module:data.Shelf#setListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 		key as an array of key components
 	 * @param {Array.<*>} options.value 	the new value
@@ -346,9 +338,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Append an element, or a list of elements, to the value of a record of type LIST associated with the given key.
 	 *
-	 * @name module:data.Shelf#appendListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @param {*} options.elements 		the element or list of elements to be appended
@@ -370,9 +359,6 @@ export class Shelf extends PsychObject
 	 * Pop an element, at the given index, from the value of a record of type LIST associated
 	 * with the given key.
 	 *
-	 * @name module:data.Shelf#popListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key						key as an array of key components
 	 * @param {number} [options.index = -1] 	the index of the element to be popped
@@ -393,9 +379,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Empty the value of a record of type LIST associated with the given key.
 	 *
-	 * @name module:data.Shelf#clearListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @return {Promise<Array.<*>>}		the new, empty value, i.e. []
@@ -414,9 +397,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Shuffle the elements of the value of a record of type LIST associated with the given key.
 	 *
-	 * @name module:data.Shelf#shuffleListValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @return {Promise<Array.<*>>}		the new, shuffled value
@@ -436,9 +416,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the names of the fields in the dictionary record associated with the given key.
 	 *
-	 * @name module:data.Shelf#getDictionaryFieldNames
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		key as an array of key components
 	 * @return {Promise<string[]>}			the list of field names
@@ -453,9 +430,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a given field in the dictionary record associated with the given key.
 	 *
-	 * @name module:data.Shelf#getDictionaryFieldValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key					 	key as an array of key components
 	 * @param {string} options.fieldName				the name of the field
@@ -473,9 +447,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set a field in the dictionary record associated to the given key.
 	 *
-	 * @name module:data.Shelf#setDictionaryFieldValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key					key as an array of key components
 	 * @param {string} options.fieldName			the name of the field
@@ -498,9 +469,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the value of a record of type DICTIONARY associated with the given key.
 	 *
-	 * @name module:data.Shelf#getDictionaryValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key		 									key as an array of key components
 	 * @param {Object.<string, *>} options.defaultValue		the default value returned if no record with the given key
@@ -517,9 +485,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Set the value of a record of type DICTIONARY associated with the given key.
 	 *
-	 * @name module:data.Shelf#setDictionaryValue
-	 * @function
-	 * @public
 	 * @param {Object} options
 	 * @param {string[]} options.key							key as an array of key components
 	 * @param {Object.<string, *>} options.value 	the new value
@@ -551,9 +516,6 @@ export class Shelf extends PsychObject
 	 * Schedulable component that will block the experiment until the counter associated with the given key
 	 * has been incremented by the given amount.
 	 *
-	 * @name module:data.Shelf#incrementComponent
-	 * @function
-	 * @public
 	 * @param key
 	 * @param increment
 	 * @param callback
@@ -604,15 +566,14 @@ export class Shelf extends PsychObject
 	/**
 	 * Get the name of a group, using a counterbalanced design.
 	 *
-	 * @name module:data.Shelf#counterBalanceSelect
-	 * @function
-	 * @public
-	 * @param {string[]} key						key as an array of key components
-	 * @param {string[]} groups				the names of the groups
-	 * @param {number[]} groupSizes	the size of the groups
-	 * @return {Promise<any>}
+	 * @param {Object} options
+	 * @param {string[]} options.key					key as an array of key components
+	 * @param {string[]} options.groups				the names of the groups
+	 * @param {number[]} options.groupSizes		the size of the groups
+	 * @return {Promise<{string, boolean}>}		an object with the name of the selected group and whether all groups
+	 * 	have been depleted
 	 */
-	async counterBalanceSelect(key, groups, groupSizes)
+	async counterBalanceSelect({key, groups, groupSizes} = {})
 	{
 		const response = {
 			origin: 'Shelf.counterBalanceSelect',
@@ -625,7 +586,6 @@ export class Shelf extends PsychObject
 			this._checkKey(key);
 
 			// prepare the request:
-			// const componentList = key.reduce((list, component) => list + '+' + component, '');
 			const url = `${this._psychoJS.config.pavlovia.URL}/api/v2/shelf/${this._psychoJS.config.session.token}/counterbalance`;
 			const data = {
 				key,
@@ -634,7 +594,7 @@ export class Shelf extends PsychObject
 			};
 
 			// query the server:
-			const response = await fetch(url, {
+			const putResponse = await fetch(url, {
 				method: 'PUT',
 				mode: 'cors',
 				cache: 'no-cache',
@@ -648,16 +608,19 @@ export class Shelf extends PsychObject
 			});
 
 			// convert the response to json:
-			const document = await response.json();
+			const document = await putResponse.json();
 
-			if (response.status !== 200)
+			if (putResponse.status !== 200)
 			{
 				throw ('error' in document) ? document.error : document;
 			}
 
 			// return the updated value:
 			this._status = Shelf.Status.READY;
-			return [ document.group, document.finished ];
+			return {
+				group: document.group,
+				finished: document.finished
+			};
 		}
 		catch (error)
 		{
@@ -672,9 +635,6 @@ export class Shelf extends PsychObject
 	 *
 	 * <p>This is a generic method, typically called from the Shelf helper methods, e.g. setBinaryValue.</p>
 	 *
-	 * @name module:data.Shelf#_updateValue
-	 * @function
-	 * @protected
 	 * @param {string[]} key					 	key as an array of key components
 	 * @param {Shelf.Type} type 				the type of the record associated with the given key
 	 * @param {*} update 							the desired update
@@ -703,7 +663,7 @@ export class Shelf extends PsychObject
 			};
 
 			// query the server:
-			const response = await fetch(url, {
+			const postResponse = await fetch(url, {
 				method: 'POST',
 				mode: 'cors',
 				cache: 'no-cache',
@@ -717,9 +677,9 @@ export class Shelf extends PsychObject
 			});
 
 			// convert the response to json:
-			const document = await response.json();
+			const document = await postResponse.json();
 
-			if (response.status !== 200)
+			if (postResponse.status !== 200)
 			{
 				throw ('error' in document) ? document.error : document;
 			}
@@ -740,9 +700,6 @@ export class Shelf extends PsychObject
 	 *
 	 * <p>This is a generic method, typically called from the Shelf helper methods, e.g. getBinaryValue.</p>
 	 *
-	 * @name module:data.Shelf#_getValue
-	 * @function
-	 * @protected
 	 * @param {string[]} key					 	key as an array of key components
 	 * @param {Shelf.Type} type 				the type of the record associated with the given key
 	 * @param {Object} [options] 			the options, e.g. the default value returned if no record with the
@@ -782,7 +739,7 @@ export class Shelf extends PsychObject
 			}
 
 			// query the server:
-			const response = await fetch(url, {
+			const putResponse = await fetch(url, {
 				method: 'PUT',
 				mode: 'cors',
 				cache: 'no-cache',
@@ -795,9 +752,9 @@ export class Shelf extends PsychObject
 				body: JSON.stringify(data)
 			});
 
-			const document = await response.json();
+			const document = await putResponse.json();
 
-			if (response.status !== 200)
+			if (putResponse.status !== 200)
 			{
 				throw ('error' in document) ? document.error : document;
 			}
@@ -818,11 +775,8 @@ export class Shelf extends PsychObject
 	 *
 	 * <p>Since all Shelf methods call _checkAvailability, we also use it as a means to throttle those calls.</p>
 	 *
-	 * @name module:data.Shelf#_checkAvailability
-	 * @function
-	 * @public
-	 * @param {string} [methodName=""] 	name of the method requiring a check
-	 * @throws {Object.<string, *>} 				exception if it is not possible to run the given shelf command
+	 * @param {string} [methodName=""] - name of the method requiring a check
+	 * @throws {Object.<string, *>} exception if it is not possible to run the given shelf command
 	 */
 	_checkAvailability(methodName = "")
 	{
@@ -871,9 +825,6 @@ export class Shelf extends PsychObject
 	/**
 	 * Check the validity of the key.
 	 *
-	 * @name module:data.Shelf#_checkKey
-	 * @function
-	 * @public
 	 * @param {object} key 							key whose validity is to be checked
 	 * @throws {Object.<string, *>} 	exception if the key is invalid
 	 */
@@ -898,10 +849,8 @@ export class Shelf extends PsychObject
 /**
  * Shelf status
  *
- * @name module:data.Shelf#Status
  * @enum {Symbol}
  * @readonly
- * @public
  */
 Shelf.Status = {
 	/**
@@ -925,7 +874,6 @@ Shelf.Status = {
  *
  * @enum {Symbol}
  * @readonly
- * @public
  */
 Shelf.Type = {
 	INTEGER: Symbol.for('INTEGER'),
@@ -941,19 +889,23 @@ Shelf.Type = {
 
 
 
+    
+    
 
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/data_TrialHandler.js.html b/docs/data_TrialHandler.js.html index 8767079..df179b4 100644 --- a/docs/data_TrialHandler.js.html +++ b/docs/data_TrialHandler.js.html @@ -1,23 +1,47 @@ + - JSDoc: Source: data/TrialHandler.js - - - + data/TrialHandler.js - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Source: data/TrialHandler.js

+ + + + +
+ +

data/TrialHandler.js

+ @@ -32,8 +56,8 @@ * * @author Alain Pitiot * @author Hiroyuki Sogo & Sotiri Bakagiannis - better support for BOM and accented characters - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -45,25 +69,12 @@ import * as util from "../util/Util.js"; /** * <p>A Trial Handler handles the importing and sequencing of conditions.</p> * - * @class * @extends PsychObject - * @param {Object} options - the handler options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {Array.<Object> | String} [options.trialList= [undefined] ] - if it is a string, we treat it as the name of a condition resource - * @param {number} options.nReps - number of repetitions - * @param {module:data.TrialHandler.Method} options.method - the trial method - * @param {Object} options.extraInfo - additional information to be stored alongside the trial data, e.g. session ID, participant ID, etc. - * @param {number} options.seed - seed for the random number generator - * @param {boolean} [options.autoLog= false] - whether or not to log */ export class TrialHandler extends PsychObject { /** * Getter for experimentHandler. - * - * @name module:core.Window#experimentHandler - * @function - * @public */ get experimentHandler() { @@ -72,10 +83,6 @@ export class TrialHandler extends PsychObject /** * Setter for experimentHandler. - * - * @name module:core.Window#experimentHandler - * @function - * @public */ set experimentHandler(exp) { @@ -83,8 +90,14 @@ export class TrialHandler extends PsychObject } /** - * @constructor - * @public + * @param {Object} options - the handler options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {Array.<Object> | String} [options.trialList= [undefined] ] - if it is a string, we treat it as the name of a condition resource + * @param {number} options.nReps - number of repetitions + * @param {module:data.TrialHandler.Method} options.method - the trial method + * @param {Object} options.extraInfo - additional information to be stored alongside the trial data, e.g. session ID, participant ID, etc. + * @param {number} options.seed - seed for the random number generator + * @param {boolean} [options.autoLog= false] - whether or not to log * * @todo extraInfo is not taken into account, we use the expInfo of the ExperimentHandler instead */ @@ -251,7 +264,6 @@ export class TrialHandler extends PsychObject * * <p>This is typically used in the LoopBegin function, in order to capture the current state of a TrialHandler</p> * - * @public * @return {Snapshot} - a snapshot of the current internal state. */ getSnapshot() @@ -324,8 +336,6 @@ export class TrialHandler extends PsychObject /** * Set the internal state of the snapshot's trial handler from the snapshot. * - * @public - * @static * @param {Snapshot} snapshot - the snapshot from which to update the current internal state of the * snapshot's trial handler */ @@ -393,7 +403,6 @@ export class TrialHandler extends PsychObject /** * Get the trial index. * - * @public * @return {number} the current trial index */ getTrialIndex() @@ -417,7 +426,6 @@ export class TrialHandler extends PsychObject * <p>Note: we assume that all trials in the trialList share the same attributes * and consequently consider only the attributes of the first trial.</p> * - * @public * @return {Array.string} the attributes */ getAttributes() @@ -439,7 +447,6 @@ export class TrialHandler extends PsychObject /** * Get the current trial. * - * @public * @return {Object} the current trial */ getCurrentTrial() @@ -466,7 +473,6 @@ export class TrialHandler extends PsychObject /** * Get the nth future or past trial, without advancing through the trial list. * - * @public * @param {number} [n = 1] - increment * @return {Object|undefined} the future trial (if n is positive) or past trial (if n is negative) * or undefined if attempting to go beyond the last trial. @@ -485,7 +491,6 @@ export class TrialHandler extends PsychObject * Get the nth previous trial. * <p> Note: this is useful for comparisons in n-back tasks.</p> * - * @public * @param {number} [n = -1] - increment * @return {Object|undefined} the past trial or undefined if attempting to go prior to the first trial. */ @@ -497,7 +502,6 @@ export class TrialHandler extends PsychObject /** * Add a key/value pair to data about the current trial held by the experiment handler * - * @public * @param {Object} key - the key * @param {Object} value - the value */ @@ -536,8 +540,6 @@ export class TrialHandler extends PsychObject * '5:' * '-5:-2, 9, 11:5:22' * - * @public - * @static * @param {module:core.ServerManager} serverManager - the server manager * @param {String} resourceName - the name of the resource containing the list of conditions, which must have been registered with the server manager. * @param {Object} [selection = null] - the selection @@ -645,7 +647,6 @@ export class TrialHandler extends PsychObject /** * Prepare the trial list. * - * @function * @protected * @returns {void} */ @@ -683,7 +684,7 @@ export class TrialHandler extends PsychObject } } - /* + /** * Prepare the sequence of trials. * * <p>The returned sequence is a matrix (an array of arrays) of trial indices @@ -708,7 +709,7 @@ export class TrialHandler extends PsychObject * </p> * * @protected - */ + **/ _prepareSequence() { const response = { @@ -766,7 +767,6 @@ export class TrialHandler extends PsychObject * * @enum {Symbol} * @readonly - * @public */ TrialHandler.Method = { /** @@ -796,19 +796,23 @@ TrialHandler.Method = { + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + diff --git a/docs/fonts/Montserrat/Montserrat-Bold.eot b/docs/fonts/Montserrat/Montserrat-Bold.eot new file mode 100644 index 0000000000000000000000000000000000000000..f2970bbdc7cced41387b330775acfe5904035ada GIT binary patch literal 106135 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 $)*$PqXnI`Dx6H^>%8=WhJm03?IcDv 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 z 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

fETNMevwO+mYTFC)@^Ar{>f35uhUo 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 NbN`kq065MBBfty~TCM;9 literal 0 HcmV?d00001 diff --git a/docs/fonts/Montserrat/Montserrat-Bold.ttf b/docs/fonts/Montserrat/Montserrat-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3bfd79b66f9dd2a59deef46385ff5d9c576d6aae GIT binary patch literal 47088 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 TV!uf}z&C0i)Vr*-XWRb)IXm>Y literal 0 HcmV?d00001 diff --git a/docs/fonts/Montserrat/Montserrat-Bold.woff b/docs/fonts/Montserrat/Montserrat-Bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..92607654b7c7225082b354f7ec641d5595f3d8c1 GIT binary patch literal 112872 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�Msr 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

M3UDXbPVJmHZvev$~fdAmfKZ%lf*NUNInSXp>h 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�O;&bslFM}<`=-aHtO zBK)(kdK=XEuO?+ZD) z*Zv(lm7qa{spGm<9@71}zy*G_Vf=wYGqKsN55-8Md7fPGpm z-^4yC%Qph9hs&t)SKlPcEn1yhJ$Y&~s&ce@4Whu>R}iUrxcEK;xij+cQfRiNtZsc|G5MBAvhJ zI>N@FdY`4;+6nQ~`lzd1Pj!7Si^rEOi6DI`m`}l?7Pyn?a~mbdgg$GFd+IkdnpSU3 zgmCITmgQ^*nS3dNlwH%RF@_h6;)TafgnATGn$#3zT1rb&#v86!a)<;-;grhVqz}lm z7r3V#)YEkK$dz5CtB9C_p|clQnO^I$h+Cf4v2{A0@2E6Zcj}UsmM9GBl9-q%3_eNm z+>Ex`C&nI{#)5|pt*q+n@YE=lKW6Hkxq3Ig>6)^LDT+M-&{|-R;pUb7+EV-BnTUz+ zCITS8Bvj|Mzwu*Y_Tl(8?1Z>-mw*E+C=r zyT|j&s7;(LT2(;!g+WF(=X9rhVkYIOJNo+QfomYPN%&uFi9Fy7FB&MXSB(E&K4alK2j2co;_s5jQ^5-@)OZAZ4RF#D-hGy$*A=*;WY^sy} zxEnbw@nT(FID*F-3B1LPVXyxr)#=g`dt&Q2om6Q!vNA?4E)!8_nsw8#GpYHKkK!{5}s?q(zLS4=b`qd*@O#-+t zgkXC0_gtl-XIk|LHH8G?d$kRAzc28w4PeJeIHg@+JDd6wZYIdcEDP*#kdrEAs8!g< z`lRlEX1Vc-M`!EtTZTCQ5D$)5BVMFCh#56!y7qru7*?gyAjF%#^$1V+Kqk%pQ-qkF z5q0&Ro^hQotjBow>?YSy-1}^t9(g-cESG~;3Kz9SH6W?#Ehn-cbS9t(_K-RjU&GQ+ z7jiFVBDcukj_a;pf`>_MS#v>w*M;)Di>v;M-gzED4}3*gm>22SH1N2PP%SyVUNtyF zuoksy!F)~A27=bkI#d=cWJ!qYqy&E_>gOWE4rfD3Pg-vVOM;-LcU)I`%wEEw8-1X- z9CD?OI21%2ZKRIA?#Q=q8<){hz#T@U@|*7GzcqCo4&yW&!Q)<{nU_s&TU%T=`!agn zn^nzS3Tw!*h^2yNAGH(N>GTGQq`LNp@)lg0d!6z<@^xd9OQ6KjG|b4z#!^iYTF#b= zuRG6g{TzKTXg}jtFflP)oJ62zd(O@T=7}*dcaC3?%fE};cZ&+MoL(ARGkYWkIN?jT zOuN#|)!DlT=dI3@hJCK}znDqZx%al|(T-RrJ+7HNN!bImL`(zBY{+9maQ)o!CJSr6 z&?>kQyg;6v`@yV3ByS{1*I&!wjp_hh7y>dH*g~M66yS=Jr|(FGMsS0`VcEw=Y>39XrQNkxs%Ua`L^4)-++xl*^7PAxKwQxX-V>jqnIg1N( z*BA>giSOQ*R~orhg6PF)`9mtPRhB4*M2QeUYy>CcSM~$R5q*!=KYx%Dpw9?@c@y9_ zP}a13W+vKgpM5rcx9Dt%EH;7{TqSqw8i^fxQ#z!AI1qr+=Mu9Mb_y$wNly{L%T%EH z5sc@njJ5;VchJwH4-)Ukg0PR7Og>qhBP_|7ncMFbN=LkNy5D({TVEoq(jfa&9p+W4 z2m=1?EZoiIRxCfhtmJs5ge~J^KYzIz0@4hc3ON6KV9W_yw%Y)CMp#fX5WY3D5B|2? zOMfKU#WAvT!;AgPWTZ@5{$5N}FX+oLz?r5GxGBzW;JTwLimMeQFQ6Vu(LKA}3z%s) zB8w^}lcS_@@d}bbcc#2kM{29anqC^3bo>>+Vua+xtOYF*fi{gD-t5WgPwH<_KiA&` zJka9xXm{Lb`2WVu7YIqxpt!}WWBGRwbMZygBSgZrx9BL``0YA6?J4ZkEz)@$Tab#@ zCoAh-Zx7Y2Lc^JJ3lXWTnOw1s&LC4hhCpnkyNWYSJHU zxo=1rHXyx#^N>zoY#>@o@}=h23^~trL_JO zcwr%Mu^j?0wN{8F6wN*<)2Tz^&ux<&F7NZTnJ$C#OM{Xb{^?#ZQHP#LnX!|*t^W*P z3Fnpdq3N;YG#zetp`Qt8Afp%R%{@Ko32&U?zg0*B#iAF}FSS~6Ox$Q}i{yP<-I4t< z=ECiGzUa~Oun^-33}(CLu}$!!{9V^C<%)%8k1@63KaOOb5U6+}P3m+Be8PeE9%RI} z&%n^*_Oe8h{k?g@9WtZUBYly3*mr)5#m!>5xQzE-&EF0(k}C)=EtS~M&Tztn8Po|7 zIwyqLm?}V_1sVwuY3ct?j7O+ww1sSF6XCM@n@epd{hkI}P#+Vvd_-)TlljZRX!^AZv*WAiB zHiO)CSQkFApD-To^%@R9uX%=rtBCK&3{#d2k;z1Cy^po0u#!Pj?$ zXJXU6(EmSe`4is^IXUFR2WE|hm8ta0C$wCWfE?FT8>{P9Q}Ti-wWF2vu0EZM1iO9_ zmg+2jX0@|t!>5)~7ysvsLzzlSuwM-)*>eJ$XgIKG@EeBm&1Ksq|V#h3LrPOQD z5iE&4Tq#j2@x9Qf6~o;N^2%{r6Zs{ZY{`&;;?lAMYl0L1B^~?g%vpvewLVYzwcG@90SIXNE#z9II*NW88?NobgK*KxJHU^^-DoJv92Unff zvj>bywIyGlupIIb3{BymQwyP7RJURSTvnK{*xTzTG!~+AN`|B`|C8VE3f`T+WUQo% zW~$Jx68-fW1-B`Ie-Bru=56F|<+Hz7MxkQ6vL;dTjK$`D)F6@4QqLw`26f@V@}>@A z)R2Piofxf0i+M-~o#eQs4985iYfU-`jH(y5TFV!%Pwj@R3Pdb$pEfs>0@i`_y!jV#U_enm2rM!_`ps!RvHYKXtdA=i*aaY&}*# z%;m@KBD7VWylw;%oh>_X9*lnymfMqmq$;Eq)Kdw3o|l-ibdcl8y_5HiV)Q@yYHSdf zpN=}Xu7K|`O0W=HV-jZ796~R{iEO&=>0mRH&vKk9PfACUBig7H@nk;wBk z)q>rBa+Lq-{38~5&Azf(u`+;5NCH(nKQnVPivnSD=Q_gR;_kPIB z5o~sOQ&mNPfKW5&!FJAwBrl_fC<(m$M*xY7F1OAXi@j`P6ee!KE`vN5Kdsq0a-$jc zwDFtH+&m(`(&}W{Y)3}?|1esMsi~tPZ^~D*{}EanrT@dj`I`T)3xY>_?^MnYv4RX& zN0=d^i70ao>3%w3iRK1W8rhyl=lw5ejsq8~!wFbJO3Je2{0A}L&kg$1&;r*|t&5(n zcqxzquqor{En_iPO-o0J4FZC66~LGSwp8(A(kG#NcQYIHI1!DIbVK9k%KNENSP_Z| z=+)6nv=xNjJQwr_?gfKJN(M~_GYG%P?o}DjsO(N4v|59xJJpU`)UjLS0>}OAivAev zQ#&25qOD*b499|J|CRL6n{HIm)&!OGz@u8o4mXY2f?63bect|t7qq}kwL54*g&EW@ zFv_T)uKXu9?lW~$Apv5M+5WWyG#BflQYrOprMbs>34=S?y~nKH47ivY3gF|+eIU&j zk6@BFX8|E!Cgh7C)k?QV8l=b^!@vdjXrThrpwTGAc7g2i#;D6Ld_ zfX8VnlaHJ81YvlqOVGOb4~7x2I#l{R$sCdAxNr}sU;o?3Z=zK*YBjo4k@jB*1OW-0 zZ2h(8tGWJd{7Ovr>PCap08oX3_xpebOU-F%Kf)WycY6}*idCymp!=DP4pV2FJl2dZ z>0(U8Xs_$>$RrY~9nvEqEj%jUU+B5x1xnh7K~eBX?Z`onvkt&h&2lM9hxNj6nttM{ zRm=WSQ(@lHHJ%eX^^8AE0b1gPrX zNz_lh+6!MQD0E*EDD*;M&<@2V9g!@?~iCKSB&rS&%H9T%*^!k zEMzxCfwWteAMnYe+l;C-dmV;gT|4}2uHfFtsM`0YOJoG#IZ6cJ5ed1X>da1Xo)JPhBK9 zgx__}l~3NEv7YbSA!8Uv91BPIEJD9@1{rE`yB*zDB3~teZSr~@@SMMKMNn$&T4Tr^ zj%W+U8ZNCaHza8{G$0lkSlobdwJs1IF6DuK0=e)oERkz&Y7n9(a)BTO-l+*5h~;4E z;~B~kx3GP~AX2A57|9=wZt`qiytw@FL_)@F_HL2+bVpG?HZ1vF*`U9R&ZKxC8fKz= zE1;a7>ezqjKpwSnbiWFtW7I^9ab(8}`Y}<^nrQkt3SEl6I$&nu+Ta==IUC?AKTOpi z`h+J>77$M{g*mP1GEy<%Pt<{wr6ST&cgrAT@Sh6oP?i+K$N>|Z=g(9a>iP)F-doy8 zg_fzUSUDRy>K@KE(%X%*$#+)WYo|I2GN7?|aC;zZwsyAhelUJQ9-ZER#$*-m#&nII zG5)dbXjjOiS{qREQshjGsER8U!S|uxvpQHQUu{Q3s_u=Z3!1gHc0+SstdaBEj)mp3 z9H@}yDLH)1r?EWGzhv={_khLx@kx?g16fZYeV1PIgP!W#sxI9iq!>egOh=Ltjr*J^bI$h`x$~eNY=h9JC>)Q>zsr=inlV-%l9? z#+ie`dI~>h5F9Z^4t5B`U+}qqbXR59+GzzN0xp*4R}U*-U;n(m-*@X)^X^T5>jq2X zA9Z?yixBU34w~GBWfl#>GS+z{G)Xg01U`wJ6Yo-gJTm~b6AXC~l`*(t8~qf_MNO5& zlp1IM2(~#sNTdLf^H3(N=QRgXgN`1fP%iIJ!%1e}B1I zNW+nPtE8y7FcMjmepr5(pL~Dqa~8u|9@}C!jOsHZ637G6$SX$ck>n*XzzX03_W}0l%@3Y*}u(w3x?Iy_bbT@YVcpV>Y*K@8j^maiY#))IxB1oOa!_J9~;aGeU0LPjzFu! zV~s>Qf|NPii3Ixy<7#anS1^1s$~S>_QJnDH!<3>fX2tAj2L?(*21#F%Wx>yevG&Xt zR!J27rg)6{zQ6sOFHww`TgR{>>RMuf3*E0coN^z zTlA9PzaK_e%HV|9)H9B%e~p#`aKU6=2Vi2g5CdXr!5(F7XHb}}G0LKGz97{hbq94O zaXf*%PJA4VSH|v@u;lUdJBTYw(rfBOJa4>`)+-4vsfc=jf_4MAzEiaEZ3L)Ll>*mB zM$5P5(j}w&_{l#V$NiVrg={L_WMCD(msk=5BifvkpTE_R(P*x+)-}k9?q-?gyg??ElX|~O}u`g>(-Md{p2UX4QK5{Mh?Hl6K_RSE23S=KEJQo!`|7 zVS{5FIJp-+TntrGQ&@#E-p8j~cdu;(t_7bx?d{QfPPZ~HB-$h6kVm=?qs-pK3jzM( zUjF&q=x8m}#k{(gWYBXnBWY=H{ib7=9H~5lAmJqKO_*D^LBPw-zs>&K*$0_#zy(Z@ zaxT5-i+Jb8z)y)K8gF9O9t%N-T26Pf%fWtvD}z`iChY2aP*81ZG=~9*U-bJyKIHf+- zr}2YDs+nIl{{O&Wr-%Ov>qr5#kOS#}pG-YAYIN9I|NEWZYI-Rg?I%WkcGbbe zEypckTd-!MbO|DeP~&qi-{CNE0RjOMCANX%JY|V&K^PhdRq8n)v4}Grx@LNtjDAZV z0a7e)j=~;%kh$(bSpK|xptx7jwmqDeK^P61t@@Q^2RJdm9h=%Z%J#Gk-T(-Obwf*# zM+$5;X5YXyvq`CCV|g>~wuZKNH4LmbqrBq0w!+HhmFnURWwK4MCx8e*MNY)>jh%WA z=OF+nEJqHy`nv84^HLF(&DQK{YhIO=m%+h%vn(YF z^CFyz3fu|{v`WlU&_L5;dl!34SC}fiBCnh*!ey5pp*5qN3IQ>KB=3r) zWR3MQlaWS#M)sB0!e+MBSy;?X_QN*k_Md`lZ?11NdKYYm54Mx+ho2mYC9diRG0T8p zNlcjEo!{&~vA*ya1i_|hRAnJ(EXEPeM>vLyu_);Tm2bbjCo-N=uIZEHWEiXhG*=(* z=SLOHRuhsso?!=d)2L@eWIbll3=>>EWF%&7t6`NM#-g+!XGN9Gt_@LD?POt6T4Nck zWOZlN_X8h6Hu2+FEk-3!Dc9p;Qxn}0tIV8lgk~DD?S@2Mi`(&B8>!>-GezKQR#Y;! zn0?Mlvl8~&z?|HA_3jLPo#3`KC2BLRw2hjs;gNB0bW5K^sxz-GlDF!L8g^VPvbNvw zWtndSxNw1~Px10*rgpMIlw8onto~E%7Eo%g@~-BQ+VAbREfy(y(SRc>_hGEspkyrI zGgC*6>XMd2!ebIs51)Y{==PVjCP0tIyo&=*r1<<=GxZ}Ub%y$pn0@7Q_hBSKy9tE# zj2Z_*QvKtq3}mk)Jfxpbt91IgGCmJ0E7Uzs+SK+`Rn z+@vWgqMc4Y(F#O$JuJM?qHvqM#gk#_h=e$9W~7gU86~S=0^r!HLN^S=5c)r^zP$B~ ze=l>e?TuzzI&L)F-Z^Z3Zu1tpUaC4@@^Ctzu=EkD_hop@{&M3Yygn4#W-j3bzwV^8 z5mqm%{gqHWN9(VM9~B&@b>hNMqMh}F2kf*LOb7GI8C-wK@| z$|VL;W?O&;;_dLh$^O1xb~im|=dPvp4ZZhmO~B@ac-$sw;^I^Sa~!Psd3^1mTa&fr zfxk4`-6G7f#txH+miK~nU%-`WPX)+O_^9d}u!+!GyWyW<9h!aXw?Wmk=&0rm>h%bH zB!7BoE-#&hSFPF!7%y0dKrkCTHtdU~lCF!7(8@d;gqR`KnWi{)CKo(Yj1xw?%#Wvx zRAyE6-8!wt!mN)OCG|k+^vI@Cir{7)+k&H>;J<=I3=}7CLK)2Kh`(XnXHm??U2Pc=8+hdNolcz-j+tvt= zsc`ymh<3ZO^g|4sSI5Ll?)k1A;#s`P=Rfx`2kIDAx|9&LvJ?2{7!AU z8T%agwMd}6#F&xJo)Ol6LgscBV9$aPUOjH^eCAkIcP@4#5f5vQ`dAZg{9}@SkBgcq zo-##qnknP`()7Ep z(>^vg{?%U4ZAL?6&p=LYkA4$c8)+|YMt@Y^Daa6`4VAfVX&<6akXR9GK7NA}du&r} zx78`QkN}W8JD}U>Qj1T^nA%M3F;>cVA?epvkt|*W6D%7RH>P*EF zc_u)STcx8v861ZjySu%k+`(Q#0SuE=QmubCy^qyRO^xEpU@X6#PGrrVLoH5fOWetE zm_DFZe4)eoDfPJ)G5v1H40`)>6Wn|NXK-vulk!$I9aS1s%YaVIswUg2%g>_t=M2}Y&pS~L5xvn}6V_dB%s zB!zdon$M>Smmi+3y0s!pgHCrCc==T4|4CNK-$z zDo@wJ0hN@#WVF<|`@9O&@0X>Dw;2;N7M2sO4f6D#HzIX~5lsnV|C8+~}&C!#9`*iZyMPY}#M%UAmtEm=6NOEWOh zd=z+5CHx9xWB(4*D8beA8lHuUV|5QJu8B)cKteg&!iJ~CeoR(b#>!?O9T$f*Kj$o5M>`XEp zBLS=Tr$aPB!y8{G4Fw<}B2nrLa{qM2U{~NX1zJr4b^q@;zD{6L(W?(t#b9PEJPfK1 zS9~ly^3?ZFe;UIh6vtmOZ*f%$cnkV(gg1aN3KTd3;zOP05bzqc(l3GHMkqK3yJW3<3X;;65g@*lAr`95+9XtX z_a|%`)?BL=GE3K;uRu4ye>KfGFInTHxKI-V$xz0;RxJ;OO7}qY*-cC!P-WE zi@@8KlBk9Fic+D$@z{xj+LDL`mr0B~;aUmYoRp64brgKB(8@u~-6ww>M7VwikqUS| z)`m{gfL=BQwpSNhyjh~I&Q4F$2r_fxc3wO(9e9?r9V{yeTG2+)bfNRK(@FE6^)({8 z5NVh){lQO!TDffb!Wi|bA0-V94J8dFZELk>(h-1ri5r%tQHUv(;43V#XmKL3FzfU3 zg!LT{?@q8op=ulkGealK;9@?E`R0$=YUX!(m`yb1n?iC5W?pDYQNP9f&(+^!taK{A zm+p;vlxw#5vcKkHG);&pPC=Gr*f=9MPwawnS^|J60-c07N^W^ zJ0voa2@d%-_}QYXjStS@o=<^A0jm4@3ZYc<(!?Q1ht!5tVQ)=!AA8w~iQ))VUq?)3 z;NCd$-gr(Cz6Cx#M4xgeP_)EE^m2Ha30HqZ$I!<+ayMn6f?o+< zGx$pnAL9^}04lI{+Q}Swsz_#3kjQgE&hGnT_Vuc%mO*9>W^VW1Je=4?&(o!x(Jtn4FB_=Vdc0xMKfz632JT{l z0-%WG#`ONm0*b($KwAGElWyl9d>tJ^(=b?Vs# zcrkzz#Hb}JqX>Y7{DaOIHkt9qS0e^57g;cdLDK2d*L`zO#KAhV?8_2a?-z!yt-bgS*NXlbB;zLgM2}`sDVw2Z~ zec68@2*(=Ob|u%W_gv2J`cnHb$?Kfr6ug(ehB@~y1?Jpq(q-%b39^e4 zD}MKOF!YVUmF0vTT;qsPA4)@p8I#s@;=&07RKtZrxYVfTi2_oepXEVO4k*<=%`I)- zK6{npSuo}K_2pj=C)eaT3P)8mYjyl?zVa-EWiCOJa(9&E&ms1-xOTg7k>Fm(y{HN)3I%<<8-VW+qUi8*tU6N+vwP~ zZB5U==4D>yVV-uKs$E~zsoH0s^yYA^%lhn24KH>-bAA~pJ-K0qEYphq(rt=3C63|Yap%YQnk8Hou^Ec+ghadi zQ+};N*$6Iym>DG+EdzQCetH>SK z;qwoF!SUEu;cqp|@G6DPr$U6!{o72xC8zcDef*mVDbMvkervyxCbq8!-o6>S$d2sb zZXT6Dq~zsp^u}Y@l^fBMKBXFi=&-cW51aXp4?8~4ogOE@(R|!@X5LvBFxj>ydZ1i{ ztzo)}eXJPv@sxjW_UeU{l(ydL;kQ3s5Su^EpIE-{!)h^cQ7z1OTB&o*nvK3aa_3|! zgjTw<=hH-2E5}6EETILjIY<1GtC{b`MG=CgfK}sO^*Q-FJM-shjA&5tq_{r>hFAST z9jU%O2IU?Bakj6xI}#moTuIvquCzFw74M-P#loZBQgPmJ>K6}t>MKLo?|Vl8R5wS) zr8)KJ?`xCr<>~4Sh;=`o;<`DvdybfR3~7PK>yD4&fZ(!0)(J;gtt{_|377gn%L@X!~RM* zwTz*RzLDGuCsl9gGmAD;jxBl|BeT2PR1C-YQhUtl289Au{0M3Ia@8(aa+>C7RX(s! z$U%=wvAUVVwMetuyO#q6Kr8!nU}f}t#%!Ylx6H+_;c+UWBWWr)IaA00tHAH#r#1XH zxhC9f*i4zL>~&W?KcRz!MO5g4#0$&st=Z;cmrs z&8;Lof)xE0GM5d-jvd+W>oqe@`rW~=s-dryHn!0Qyx})=hDXZ3GnsDxnAzCo%VHyq zF|e?(7O>@2yd3*US392VuSmsqbcAaUa-WF2Ng3B(BbRR-EgmO{Cqb`!Zvtr`GXv__ z*rl#$kd7vkP9?UN=tE3RBYlC@w1b;Ff1|?RYj2L4*_r;T%*YqH%%E zoZ^yz0qR_F<}zJ5RYXg$_+V8=*X?9_%#6Up*EUhD#W`>b!#Ktz%Qoe5V5I2D*vLyn z7#Pxk$#7*u(WIB!01el-=oKJbQ#73~gA@<(E1a1egmXsbVAwo|Zn9eySuLYVo-vjtDnCTo|s^` zK&TmzQ`)d09vM3fa^%*REYkL+A$_|j_%yNp@%1TxdVRd}1vI&%@xQ!gVt~5RW98UKYQy_*17Ip@kh z5Esa%P$WVLt}Q;A>unq9=)^v<+rW|?LvV7k+rXh=HEc6*mcDqFb#-^^*fZFc>HT^K z)?ErFuOl6vbd21272i#10GZ7QGD+uFHp;1plO||4{&)Q-v&b=eb?<(p_&B!x0#Yjg zC-sL}ma*N$@}5+4)twgKjp(Vk)q2%ul5_S2B{5oRwU0$y;=Yx}GXGr03Kjf$Lu-c zjQwB#>7Wr+94DvCs5WpYS~l(MC{z-i0y&0M*pLpmiIEkS7&pt~`?acT-{ZFxZ3(-KJNxvj=@GpPkH>ePan zz+X%!7j!0@!=pj5!)Ong^1;-hqRfC_dk)9@-3{%JFzRsgjZT9Di3|ZA-kP1{#e09g2d4HwXgWSrD9AIEyuNW~Fxy1H&s&b)V7 zo4dNNsinG>gOTo07xE!5Z-vuRN%G*3iA&P7IXey>C~}?U7wL0orV?5;YzNxjJgD%O zxc9m{hoKi4AL(IXfPwlomLukr%-?YHbn*&(8xpn5Ed=_MhaMI~I1=SlTzjO+|6o#^ z*@ukZen62G;i?EMB(-QXz?h%jqGOY2@Ho9Ip;2o>?g?D)R5H1~?6ks%K|8u-ct_nK z(A?2mQXT?Sn!2C={w)vN^3#9mPJE6I45bjnMoR}q|0ISnIQUaG6Mb=b`Tg$mhS(DL zr>D#3;j*Rnd_I*~NO&)%%AdgqUsI0y!c0i{pBSIT*`{J{JC%-cq$V~aMd4q(CRb`v zevQ!zKCc|bcGq=b#)IR9DeHgKE$yFI1SaiLyg6>il=ZhDK!(WFiJ3A-bTnw1h;+b%QvI zj5gV}L}GnbFl^5dWMEojlQ-H@*Mo(hesOqS0M#fdQ);1#V`3q*M9Lk5bmZ!%69N4# z2}azlccFJ5W*#^Obo*G|e}uVg3xc>X`XZ&NX#efp`9Rh`nHK6%{Fk;4=AT<5A$Gxs ziogrIwRcVFW!_1VSEs*yK4qFSLxjdA>XHlmlz|~1DkZz2ZNCTR_55eUi}(+OaFdJe z*|O}TkqS8G%KSK1IxLN0bcr3es@_!7Ax_*LLu0wT%qFp1)ctQX|w5Sqd(-O@=$9$ z1Cw?sZrRgI9p!Nh>3h$xXF4$o3(@5b6XV4NiC(K0Xz}NVt+u_%ejp@%VDKtIX)nK5 zYvNMS-B4?EnYT;7ATE{`+-Tn2=eL9P?swFeq_r|mGj$BU^KY$mhDOv1#W2Nji~m3v zgIYL}8j4-vVfB4~9Y3JdJ7ucX=uHOTkD+6Riy29?9QKTyciLxm)lAt-*U)e_Ies)Z ztc+Pmwh-}V`$|N$co}|*OPKy448)Ze&=nriIq12_A-63gx$WB)%6*|92sBqCsIKO37kLQ`W}Erie~~kbx8nTw$Ym3iVD0H7;59j@iktN zcQ+*4DYo|8ZjDYiTGiW+{pfQeR;=NlW6hjVa#QkFBUsqh)d#hmXc!my?0#s!zbd%8 zT(DsC0iq!&!*MP%Jp}^zbN6078k25g6?BHIeva)GjeLe9m)SwiGxp|fOLrhv4yybC^ z-IO3IJ3ngVTgi9i@=$=oddT%=#nA#4jgMNORY6fV$^`P~o%?Nvi0V^nJ4Si22VS_b zI}DP;Om_MbJz^uWC`~m$wIOla|E0wpehzokn$g84)iVPb?)DLkig_Kf3ex60uM!zh zlB0@Aw8jd~7yFSRh7+m#`}f{&Omqv#jzAu$mF%zMP^6;CDI9)&mCe5jy6n8|BmutP z=PehVq$@XAZO=EG{c~pxnoUzpF;Lnw{;YYVt=-sRz3*qY=r~dS`|Te@%jfEIo|^&3 zdtAdd1O<#T$A(d?6f{c2bjRJMQ>p*yyT2Tka(_75j>j@|Y^-~|E%0QRHF+<+-QKGF4XnZnP5EI}YcddGQC=0Q7^+sxz8tx=Iv{*Zdnj z2#By`s}n?A&;*OGFi*w`UONcok3}REBn6aO0jP1E?Fc6cqp`nXfT_UK_856$y@Hb7 z@xsS~9}#nC*o*Sw1}B}uL3H~%Cye(8GqcpR0tZU0sC|7*qkXe|iU#>$?f>a0KW=KL4@{}F1)FIB{>6!$Iq94F$0ch2*G!MCM75TQ{TR?z& z5RPpV*TAghLygxM1};}`yvY_GO{wvG!zL0Ng#0ZA47oQ3YjnQ18y+GQ1*s9jEb49* zR2S|HtNoTTvt1oHN0bn2#HIO=rtbs8F5wYEEUu5?dUYukg5mUqFz~u zvYLVZ)6+px(!nKzEQ((L8631R7zTmAejuEPD_+Gfu|@EnTWQC<*lMYXq8hxu@883CHQWwY2V=^Ym)3}kR`m-}BE=crOmz9-`-oiVjF+mZZ6Wq=(ULEUlQ++a?@|?SVZm5HxB){TXMBDj}`0IW!2O) z6;@Pa*QpQc3wF)|Hzz0Xvp|UQt@tLBnEt-@kB#xWtU#!Luhq6P_{xfl3G2)MZQ(JF z#hKI4rytHHwnBGnO1pPXIh%Bwgh3Y%W-jhW>@;?wZY>#&EwDDX(Rr8(I|lvax1~8R zCdY09JH)dd4Zdq=Ad5kYiEfVk8kn*1I+h~!Va%75$Qay%m^hNAxGpEh^|iO{JG!LW zI(TVkSiHA+wl6u3-Sd6@z#%`897&xaa;x7xJ*3f0^|L^l0wf+9PSZBILsUlEZq$D~ zu(0r*|2O7*$?OBkQ;=P5#-w@UN9wBoNFzb|1cIa|eb;xI{f>sYTBnwbFAZM>XV){A z;LU7_9C5r{7k0?iCoO4sxyU%}2d<9)`OV(T;JaU)Lqz{)NhyEiu|U$qXFfsR|wEW(!w2EWM9_79T|7GqNrB+PZ=uRE34$R&n%rH?D-E=Yy0I zvPVWa*=d(aU4kB8m&f6T#vgk+2^Z#)Ea`7(Q?n)E#U=L2#v2*30C6pE2PVpD%J#&J zlA9Fz9FGZ?0Wl|MjhDOg1+q@btmPWC(wl-t-&6T4O8Ds!2CYFkWgvH$*t>6d_w@K@ zI(gH1;MmXGl!4U>AU1L#16~6%)ZyPX=)b{3qz)d*39Z(OD5jEf#T9|jT7wbvy_wTQMvfXt%y$;XANIIi8 zVXWC52le+<#d)&nf9K&C_j}fa)DI_gS7G#R?H0`wyoWQa{ft^9{rRT#V7??^fi2?R z`gYI*sgub&z;gF}tQ@SaG~`wr&PB0(RmL~=oLqD*Q{X0Z5zueOj4wVC64CNLB8D## z7h9F`p8WTxLwrOGn{I0K#nsF7+tJPJu3ZlAlx__oM@utDBJc6E4ZrW?^QxIo?A4~v z=sz*qhb|*CmqKLfo0>|lRSg}*WBShMW*9?C{QA#Kd%npFA0Bp{R0-=gZXyRHIbv$N zD**4_DAja`MVs}hmd983B*uKlT#m`xH6Od&9x9+_hLl6r-tqL+DA4F7l~lH)UUd}_ zw5RpXHwq3JyW%*{w-->Wi|cFo0&8CTQhc*-d5!W7$1Zn-3a}j|RcpjOcRyTVCsbkK zyIIyPNBf8$F2Y*Z)qHM6E*cc=FygO4gG|J^C-^nuK28}2^r4x;`I=pWAL(KD_ApLl z(=Edvw!mcHC0tD88pa|YaX%wmY{35|-%Y({%gHr5vwW$`_~G@!ksJNch)FBCo$y+% z6P!VWHH?mS!6EWnfwHfgS6GgyZ8+sS*@~dW^_ge4(jcK_gt54|FzCVPvlME@^-sex zQq)(bg83Y<7@KxTY)a9r7kE+9CQfX^@p!bV z(@$Yc#fr}S?WD)s+S4N^hqHf@lXGvKE^Dkdm(9=bVua@eG-u80!=sr`JAZR~gw6dh zaDPE24br6^i>N}chR-;1{W?=$c-Xx5eZF2wJ6Qoc-6$2;IS6(>z4)YbrfAxvb6foq zv`<|v$F#RSmRUn{<7_0bH0N5FtK+S&cJGV!2)OsQ z+SDq{I&+2w_z?jOIOpHIgN7KVO;Z<6PkE`4*S9yamH%vh|IuYvh1zX?^0$|+t8t;{ zUFTlljLk4q5v+Fm987T#(Gm0`)r<6Uy1yHyTKS}ZJ|8Qtvy>_H zyS%Z_zCAb#Y;O<5b#Y-WE4KWjJfBmMRa{)FI4^T~9t`O;PMeWIGkzR?#~9j0R-i|+ zKw7I|@v{5+i>>!36j8}8CauL#M2p=;x1X8sZlBF5aI$I&U${J%=h6LSqaT>l)f^n$ z>V@KTw|uLujqR`jX67HFU}y4m0~3DZfY)@S#@LAgINwWjXM~i@(t%Rh7ozCTqukve zjaT)kROKfk4pj`>Hy{YhSC?f$I%$)V8s@LfSrtIJ!i; zxnFCCd0o7NCer9O6=_h`znZNri)f<4L$Qmtt5TE*IrS*$t0ZL03blt|ky$D*#sgUe zio}~CfO*85MZ3NR^0ZPO+iO`lN)i2x_z{&kf?&Pw2;gD?ly%5j`j) z=I7FYxoVKj=c5Lz4{Z`$jns&6s%D`*J3&xldKG{1!vo!xJa3dt4(N1HRzUsh0@gALJSceiG#qr3Jt6mCT5 zPThk$Pkq!vdgBVYgJk2Ln^ru}NKjQz4lmD!qbH-lxFV%s014GZMM)g;3fb?edoHw)2uQ z6QcnTPS>5^+z;YYy4o6zk}u$dN(nuCW(&?bU-c$5-z%z_tL#D&nG#nd-1k>}VML6M zo-GG=3Da#4zt}wvW_B*T1kPwmL?sxBtUf20?w{)tuaaqZZWXg;pOq4!r|X9xjy1ka zS$ou9-eJ5!C#%>!083up&ObBk&F*`6QDV-6(Q}l*CT7Njcy$(doG?kxp8B7$5z#0SRK+2sl(9f}6tfkCpY%HjBRyWiAJAvb0b%i>UC{;9> zn(Hcxvt)a3VZF~s0qXx?6)neT=ibulh?cnDhH6?(0N5=cZKgIXqvS4f*1;svW61JJ z{MWnN_UOA=s665=Bj2CGko}@uW#3pcU1pBi-x2Z{_R;CNX~TQdpJ5A;jr%h9*3eZnaL&%7<_)P*mYvg_2<0T zu_&|9(yc%I-Dwy!NsINVo?#?1#d{7InTe~%$j8wMJZoz09T4b zHkM;#)4+*3I2O!_YU%pQFt4$hkCMxF62#{iX#!0V*dWU15GgMG59;7Iub9=I61%cc zF%Xc{oOq{9QtI#@Usu9wtW?Z)!TXw?T1$=DmCO9ID%mRZqlS4bo4hYpiImE(i4#Zr zM`sErijxp_=!%n1LWX+Vs~3L-7L3Qor!{ZXR5O9078f_E_M1Ia+zdQ zO;K(0+Er1lE7BRLgw`?MYSY;J##AvHDCvQF+YP=pS>a#0dR6d4a`ogVb_CA*+-Fnk zczMs7e&f58{Hp6Cio#>aVPN;*z`c?~`$N_(SVStiP# z)?7maWrb!xwYe6nVg5O4%Q&wR@3&ETiS8DSq5pNm1GYOP(Zc~7Qhu)ffD9G>5g`On zVaU`rxT{kne>cNLC$(l?>On^S_Ayp{j|GQVK1IJMh;#Hp+)q}h29v%@Bfw5DOD!!1TvHDu zh_po4_VJ_BT&4@z7JP`dZR9dIC*RK)$=-aV&hP$ooi$GqEwA$CZW1c-jT2?CZD3SH z^`#M96$p@%^H2IDfR=hE)vpZJ&CR8oPrPm|>~{6LzX-s~**IL+&SGPAwEet2vt-<5 zt*x+juAbTg42i+pVTY6{#IiuW`P&S2*Cf8R!%isX=zCPDd@-kxmVi%8DZR?_QTmKN zNinf+vT?2!JlKwH7_UFJj>R%CZZ0djd3omexadk1gQ}i_|J5CNp03tBrWcDN96F3_ zRxQeb$$zc@k2>-JPA~P*PIa>Y%tPYw!!IT7;gotlO&UGq9uvQ5m)5Z-SX;;bZ&+Iv z+z{T|mEymM7nUcTP=ba}R+AHUH<(+uHlt3jl0(ag;@sTg{X=^f7ly0H!8Y3zO+K_w zu%GuDS4qb*K*9YLV@V@cb;YlI?W@>B<^4qi!!{h~;bTzo@o}p$)?Q7?AqAkMR6+`? zW7R%6{rrG=R;!dEJU6PItEyC?;utwA4Vp658{r(uee6rD_^AVxag~LTkvlL-NVh@t zh`i8Gsr=3HuU6Q6@N%(Cj1`tD)}Vyu)Y32{{HU;_rQG}7W0d+()dD5?on7;{&3|hp zhV3m_Yfx1k;Y^}+(rc(JB&#g+B-}(T{TQjK)+1J9>xg5(l#PVD9{}Sbli#cK$UP3P zw}_eDul=zpjPg@8f5LUK3DAkwm7Y;xe+di>=t*%8VGDHU<1 zr80@6$ZX6ytVzf*=-#o__-)K^&d8{}eaGY%2wRXX_kMoYPRrYW&qz-AkDh#R)62lL zRkPAovc`OLkT8T2kTVcT!`}02r9B$#b8rpxX8b@&m#)5pGAqY}9k1|Ye#0C)iefkv z?+vFbG`O6adljE*5EkBK3#eHdOe=D@>WwYcDnfv0(zeK+(2h#y5eU z)zq(Tsr0V)}+f^_u! ztn9QiB+kcXW@fe1(?dAlr3J%AhSfFF#;ooARykIGL*J+U9os zB<1!2k#bYBwhOWs7U$)$+QtySEOq30h?&!xt?6FnOAcDvA-quhW^ zfPDLDBvj55v2QGhbHYNOymc=)@@)AKrMY^Ho9DJ;YT1j0hP)!ehp6?i1Z$mtfhtxR zV;cQ~9oyv@@!2><$m+{jUSsS2B`At@pE$@fGA-H*?$COj)$#{sxFspU;4&ZIR^ftU z4?yKhmSjl*ic&!w4ca_;PMI2HL*78|bEaYCEOT_WN$LZ6Xivo0wB~9}irY_YS6)sb z;LgBE^qthxzh<_JrLF%Ss*DP2g+dbuOMXLWm35xsnfL&PgyI`1hn<)J9pNSf`e4Z; z?X61;o2*G6gi84i>v8;LD*O~ZgnEQIG|>V)Fh1hBg$xC)7|KXVNv}7D9Kc+sq^PMT z2rb(I2cD424K?2P+YYh47n90#E@Q=x8-9E}-!9!*vTF`2V>2?Sy)q*;yddZdqg$i} zDSD5b4^8K70!e)azPOw#(u}I-U13dkd34Z>_==;$26(Rbut6b0(W5~jkLBR>0}gwg ze@!d{HMrb->s67rt{z z4C6UM7M5~z_trF$MAL<(X@6o)<2luQJy^K}W2RyXWDg-e0_WM6p`a@nM#MzBcxA8k z+#n|gL$H1n__!H%ZhWQi-$XH!G0*nDq&3IUJ}L1YRAp@>BcW5 z`3Y+kRDAtI7SEqI7V89=7*?IpXAsQO z)u@ouh87Og+8P!A>h^HrV;vW-zAKpxLqcmkNr*VYr}j>xKSHr*R9M>1+oaPi^WYb~HX%i$a#8eI;+TuWIV)X{e~Hi{-2- z=ykMBw&ho}vc@jC9j07FB20~=T-A)v)YeST)CPX_4wf)&qmh4$=nzK;IQNPY3V&%p zg3SIti(yN4m-@KZpu23Y$05e?y7uYGltVR!#LM|q(SD%Po`RwJ$fcIM)AScARQ~J= zRz|NG8Bms=D1x>R+Ee~u8LP83sSqz#8minApXwi#IzcnkmE4!3nm}AGIPIV(Vmktc z%xnpnNq-$Ln!^+Bl&q}J9mC(;gZAzlh~G%Y1hk8(z7-gr!yJKm{Hwrb)lXKwUH8c@5S8qnYUVHHhlA$H$=|mnQNB zrEW9b`>V)wy@chXt8xr1w$!PNbv`RKP-b>*H~w;&@{#zb#x2p?U1KBB9e3)K>bqa< z)MMA@z%GbY-I}YDl~s^(K7}|f^|ZwRvAi3FprO-Ae0%L8DTz)wt^cU~<~wdmwe9NZ z@?SkytU~0BkRg*+r?GA6xous$90?d!zb9&671)MTGjm!N5Yb$lO@$ zWpH=2F3%;3ln?_hyWn=Y#`TbblA8=3oBMCoAOGdZ1GKib=@R>;OfJGhcHuN#W9e~} zsF5TRMMVPaWSnGuc8F(x2dW^<=%ke_g0WX)Y)0H{9(?c9P*UCyD^i-KruI=(;m(0e zhfZt{0c%%^v6-pHL&zg$FC47NTHQ-+x1u$>xaR5?a)4+*qf>$oe7NCspjkXN-cWWY z1E)#)iaqstl38HnonooaTdBe-bpzf`vNs6{0X7;YngyIuwJ@@99ScZ!+Sxb-1zK<2 z&;6Rx4hgx3+naJsUUKtaSB74$n${PCxukZ*Po7&g{e8yUF-FPp0p1S zw?9GQ2kV&*EYwv_flNN5SWY_0g0kScKK`Wue~=A52zd9si63uI8sFTpA@4)RJ=c51 zMV?&vNha+GFODmZV5=o0W8e-OvW7^6rFl_t@xYGL-BSihCNG)LOA#O|N&H)%U11q|4+ixrVOMPxNNw__@DeoLqPQ?OzMzo2}yk%FI=DaQiph~x|aiJGt!1S;<9y={Ob07#W6Cw6PxmS=#<|<#$iMG0%LiQ@5A&NNh0n)a_+<0>)5$~ zovEv>i;Js`$%_jFL?8drbN3Bj#B%OZFgV$iv5}!HvHv1@2bf8uSH_0`7(nq2JnoTx zl@nP=SKgOi2AKBP?SKkianvQ>fWwvm-hPkC=6SP-#8=5R#L(@Om$L1CV{$s^T> zza|e9X6^}WJTk)i@?Ut-f{NU<^m)viH9gghjvupfnMBz)slM`^^-Unl&U}N;ib~ba zTl3kkr+NSsv>mS1ww|+d&$*D-zPrhx`~Don^d~|oIhCLFfdF|~{R!DV=5r%n_cr)FC8K1Kf8&ms(2JTFwHq0AKn*w+anQW5RLaZ{UZGk^WVY}3&SRxa4I^`h zBWp{sY0|@cIs6rRs!Zx;sAB2lWpn?McAy}QMOKKq$JPYF-cQ=V0oT74_CMM3AY!iK zu>QKBo4j%DoI=1Z-mmhQ2w_#vA?`8~dU>6yY;xd79hy0<5OA-mO=OX!-{Kj8MMy@U z3KtFV@Ikd2-l}9n!Ch8YVnZOb@TI%>f^6ldn; zFfu14wcmJdo_}$oA#p(^>AzeZ8U;i4gNPwz9TJ6vr{ zQX45li0NtzGY)>xYY!Se^%8O9d#1DFfSnx}CzB}iTsoE)a_^e&ki1i4cm6Q z>xGIM8GIS+ZI_1=6)L-Y_MXwxi!#6kU{Qe|RjdzNgrvxXWM&}X-HQT6MbqN=G4)iD zgC;bsCmQ|J1fkyWb*6Q~+lzyNgh_3%V`{xO46KhUZjBhj@8-eGZOeIH4zOe4FqEu5?$B1Zt-AX`x_iY^&V8}Q2$(i~Ohuuy z>$fp(0a&F`1_{&Pu{H|0pNQRzH?5rOUy(hv+q~{GxJ!DEDIgv*;3Lbk-}t6tVPFn4 zNdQBRA24!}ZI3FG5ipeEZe&|fei?hL${8rcAL459C4zV-OeTiU(ivJL%)%cQGkp48 zfqM@NOZpRAPnlN$-{s*7#G19pt9U8Z&*p{U-+m@e%Iw~=f?F#M^=}a~*S_{E#v7Me z1hv??RW$U~x*FQr11I6JB{ClJRoza#EfW0(|51^i$dhCIcK?U0DPYBr#QT1)a2r`m zhXsw7{F7~BO^%__q4E7#5!~Vv&&|p34OYAK&V3isT=D8iXw)vQUw^zMQ&wrq-PWd(jY5*8NQ1nIr?apbef|DJj8 zw5_Y5tg8zE=q|5msjtr|!3RME49|{_&kpwrshI+#Ht!l54qeD?(iu|^4zaM0kCMYR z1O82E_OuQ%jzHmOr9<<*C+t-eCYw>p=+bdtBHo?iIuUW{#1kq{v&i^FE9DV)*d1I9 zS3K5e=^;=1huTEFbed}~Xy^nu1qi&qeBL3X;n~F<1;3DGLRd50cz1+9yEq5l8=pG= zz=X-p*d5I=2S(ePSKQkhqtu+AwcEPCtku+5g#~SH3cC)uZP$SZA= zZf0@FCZS!LHXQHN1btQH zk26Og=ZgFzG%+u`psS z^fL#}4KNc;1VJ~bB1$=MQlHZ$ZwBa-WEbX>D@8t=#@m|(~wFpdOMGXC$66Aow)W+*nO zm#(HXX6P~0qy`&~nlHA(kNUkYN5q#I4DZqDfTM8{{jK<~O+$5e+DHR1A#o%7d#*wS zRE9uGYOM-nb9H8Gp!Ge;v01;uO%SME?KT>5b!E;VBo97@o4a>%N*Xsf^`N6P;TOM> zzJ)y8PX{{<*RX%aEfa7&fbl*ZWqY1yAPYX8pD}hs-wudO$ov<7&~TIO6R!w!?W}@B zMLWT5-+X4PBy!2CbwMRF8?f*TRxTi-WCrCYx#aRhfpJOHjNd_|R+*D_^l2cXoO%o+ zuX4NjP`9{E6rf#@);D5!8##AvAqbv*+ecqfN>~>aP!`LY(F&7K$sl5?gl06^BlgF- zO|=sOjtEuH=b(h%ApNu#OibtMxh5(u-SqJpo$jw*u5G7f)iLWKVhAr5)OyFV?^Mj6 zZ=eB5R)@2WeTBgC7?!!OqLhYd#ld}M&o`+_$>a*l{KW?V3!dcS@w(37k*>uH==Xln z$-35NH-YWOLC?MNej27G;4Q^2EvH$%HM=P?tzn}jBcrN+nxOS!sL$8xZZy^A)gr)V z$#Nwlx5;7Z6me`REp3IBg0Up^P<70G#z@CY%}s7JDi248g$*_>4&2ulDR5^IaYy5_ zYu)|V3}#y`FrmB@q~@isylQnFy0c1EQ$50L)Sg}Tt1D)@9?%ckj@|ohWM*cxKL`AY z@TBeozFH3R?z}kZE!pmWF=$jXl7q~^d9JZwjA(uopQ9U@0W0%@VA0#QGr}#Lo6V12 zv`Ug=qbN~NfUIJjag`f;n2C5F3+fZ@7oQVG z4wm&jLakXuMQZ4y?e1e0nrvEt$I3$_zjP$abVHX|sdjzDUSRKN zgUv#B^Ljl5&+7$(G7b9^>%SHWaxl?zB5r1Gjx&t}wgWG7cOU7Q&r1zH0q#ClI1FO_ ztSG*r10bX3?a<5X{Y$e!YeC4}5f7h2@b7N~ADE%nTaxMh87F+tNjC=uXXbhLVD7B0 zC{_%omy73{zNyTxu-m(oB=^mJ7BE0kaM182k!&(D4fjE=nYhA<=X0_l^-Ud^ALzKK$UmHfk~VAWW_C^tbvDYv$U z2{bQRT6{0{)u?481UjBX3%$4;6It3vjAoV93Mc5Iuc95C?A|YXpM!#}bCj)Vl}YlN zv?DZ1&Qxb8_|Tv)mnChPu+qFduieONk?nRtXc?WyoT`T$mBF$ik0QTWt^sl)L0fTc z_pHqDXOCd;619Ph6}U7I%VO!_wL`1RY)NWQ`}?h&6*eLQLZkoNXA0KVvhl_F;!1Z! z_Mf9;m?N(+TAzbG6$&q(j+b-Z;dT5^xGXJV?U>Ih0??7x`o=3{h-#Qz+$Ul+{)vHG z(0bBRc2x&ELzt}>aN}$H-VXP(3)d}MT6nQcJU0)UWP(46LpQWbK}_2a8RYDbI+@EHc4b;9 z+u2&@PJWvyCe5oL7Q!rBtPidr=lOUB@fyj)-COcDk&rU*UtIxI!j>ihA_0@7dawz} zP}6+f*L{C#|6N}Z&%JXctV+|_Y(?|*lBH~hq#=C76}oe^LJ;wk{-*JxwtxP#V6VY< zUO59i<#lrs<3}+|6nYDpQau)FT21ChZ-$TPCfx0|gTJddm#;=ATv&9*04fKcj>;}F zGA@by^?#LC7Y=HhiN^Y)p^qM->29kD5~+FDjmL#MSx}x?QH{KX)1eJxnL$EUMu5C} zQqaf>ubDUYZkksV93OCl587K7ce~w@6aU(5I%DtVmivs&c_{BkYn+utbQ2ypEoq6|G<68}hb10b7=(CcWkCuWDeK&V^hI3@_ z|Mh+3!Xbu#ud{q=nYdg1_|%H`t(|z-w+|04{rSOFYZr|;^7QBbH+bRt_xJp@ULkRS z0=KWWc&^&s1eI5ZRMKVcdoQe1hxmwXv)}ZoRQQbq-Syvbn83gq& zTy*ytHHhqYI`XL?iUf4+^+ID{z9td~=Q+|B1aAkLA?mqz7bq|PaiRS(T8@LCZ23JXV)x}JVL_NwW8 z!LPfK>usi|RMz10)g zor4tM%mg$6(Cce7G&gV7ncF?a5!?ToyvhI3?&#*Y6*7+H z$rU->&+&9(Rfy$_Pao!{425RmfzV=%g57zvfcRaurqrBV6IxviXil;XS#-9-ZKA)h z+UTe)w==NOn-}Y0yhGWclDrXKyA{FGgGwEQpIh{7QE2U=DT4Oq@ zkjAyEYA}!$be9_p<-R*zo_#Ba&KWcJWg5>7t=#8v-N|rYfVlT_+*jeLCZZ1Gp3TE~ zQZ>&_97dkf8RRX@nxa+-Q%b=I@CciG*rwB7h<#u_a=?*9Le3x_@XYi?>K*heSV#5+ zx@U0q&F%~z<9_VJ81_L+Y9-{;!>@RbGvA9|CLqqK;RCVCT_xe2fhD}-=L+oouwd6N z@h|lCebXKL!Zfn-_M4^lGs0(S_<-{LSLp$1L~%A!ZgY!)lJ*IO3!}VIwqWN@NPK1= zePZ9oJf0i&<1nlf@{o6|j9Vn}jzwXRv~ON zhpmmSr#x?T7L3n#@*;G@FcC;5lA6(aNM51@x+QkYwu36bEWQTAm$UYiI#e^s+aTmE zco*8w*G4k70q=_O&^}7Sb%ZxBTt|5G<4mPaA^7MixcNf37Sf67+u-I=hO6=%s@W79 z_t1UtF6WT8|I$n}&)4pMX-IRK+=u0SoWKPma2L{aGOkUcX;fHz8~zi2*}= z7;MvQ*ne0)$F|`|T&~{5dW)Zbl;n1}5q?Nt$NRha{oV3?C)@%*qHp8(%M4A)t}Gt=Htz9Ag>}0 ziKOnFF5+47ivGhNmJ&@Q&ioZRr9{ywsb;*uWC`TcwGj)-IIu`Z(q)pmQ3az*>+T9aC6e0s)MYrZr(BCr-3~1DiqI%HU2o%5}#p7;gB< zV=S@zO=sq<6JgmLwl4~X^`Mo* z_D8J+tOvCmb|7x$I!Jq7OFA)dy>5 z^udNmeNZ2*4+fsF97w6CC}e6fZ4mE#quk*vEps@^C4G<(Y`>N3gXrz1D1!A$pols; zOC{7ttAtNu%Z2!a<@hApTJCU^l{y{e(_e1mQysE^hP=PHF8Cq^~t4UcE(R1ugFdFdbb}m6j*aBWPW-KeuQm1G*|OA zceTP#laZe`;Qj0Q{p%HeYC?Y6iuX_O`zI8BnoM57@`-E>NDMX1Noz?LGEM!wOtWO% z4(IZ%c@-6Tsb0^HgEG%Fkyr6KiR=uE)MsU7)srrzw^3a2kpT8~+=0E#qpg+LUH6VF z;tH~JD+!VK;&%7|eu(&=V)*0d&n3Qy_y5T6^Y~Ht$^B}1c?aGxZHz|Cv9rO(fx9Z>2@ zW5M$@6C&3Ifkh;PfzO}3{dTM@7Q)ZqXYzTdtLZm{3X(<%N?A`^4$Nwzk3R z7q6{s&~DupKX&Wt)whntZ`-P^uUy+4FE*dJBo!V@y`-0)Gex}W=#Bq2ygU+KaKB}* zX{u$SbxU2{mez^ZNz-0y`4@{ko}!b!rm7a*&PxqTceS?eT57m-r>>>Cu_8(Q-Kr%? zke0NB@o7P!mxJVy66O<@Z7~TN6=uS7V}ihhI32@JLpcNB`6`J9X9RN`9PE@%T9{Lk zO=-z#?9>rQmoE)(czy7dmto`|h_~P|rlPjPele;#swYct7&5Q2=2+~j3fc$yPp`JD zvZUu`ukzFuOfE=Yw?Ai_IY+f=hkIFdnh=}Z8uq>5h={i%k{D(VVIR8)sGRdW#9q+aCT$gmy zk`3iItr$8zY1}aeFt)=ud3tEYP30TfCYvTL)8g*|AYpw!+PYx<&ZPtTlob8I z(w+6e+O>VPmC~P;wFE+Uhx`;!2eOk}gDKhkG&<2Hf&d9X1(iI{94ym>W>lVLjQ6U6 zkbWg$>Ixd3SvI1fZ_oHn+w#cYZH%^8!lVz38q(?+&Q_b@__{dD#PwkM^l>LYNI>7-kd$+4i+nx zXAL~D$G&oNQsRzOHok;VJSs?%nXgRP^rHc)2A(RICBoFMAzEz@JNezKQi4oNKXHa^ zoQgQjW@najK(qMtbI;v9I!cpi&6kh#^)FxEPZu1K-@o5S-ee(8wohZ@Z#fO2IhHJZ z*J*%IC6hV94?4u7V&WI*&Pq>WObUF-^Stx?f$-b7@aD3EO%tnc>g&5{^+eC%;>pIr zvLf*g_Bw_s@l|(`dh7Q1(OcH6zGWWx(W9smoC4mO_)AKzaS3h zH!W^BRFW6GVe!hV+SHBkqyGM+3|C>^{xbh~Q&Qr!{i!*QJezr+-B~%_l$Ju|G5-^e zc`D0I#KJYk=>>t!$w@6RHb_A}MU5p=m9aLkJ&9DOAf-#^!Cp~9^QFT_?|$t)^PQuk zcUs>4+TZSlV(}-^H3~)IPuVr9%(G`n4p|ypl7iGr1&xk&Al2ePt;kL_ecl_dfP|1zUrX;vwX!`5~{;W4VaB@#?S?%(c zKK-Bm{O3QT=lzxe|G@5}#fMzgRrpQD@q0)Y3)_`r`!Re^NgpRbMjY-dsWp^mO9u)p zP#plS37&VHQ!6FU%~uvhJTk<2VH(+&!-2MO)MKe({tnK1bu4a-i_jypk;D@g4hIKOWeOf{0c1D zbk9WGwrxb7AHo#U!Njr)X>nes0b7@Gpv7%f4bf^gNF0n3;0&UtQ{X#V@}UGa%ag-V zg4rm6#2p}+GYEe9AlZj^1@*)P`Z3EU(V5Ze-bz5CdyTxoW@-91)(~=Tdmz``W zW4CcOgmVG1%Z^;zr&6*@x2y+Pf585!4cFhzNB|`pZnPZ`AMWUAJ9-pe(5I&8`B6oUq7 zmtjP#5Es;6y?iHx9UJjznWHI9%UCeAth?>LM^FFnSGqevJOop@6ThN+=v0QiKcQo* zdHS^@P5%BW=*QI)!FNoIN((@vP6CyN%5n=Lqev^Wxecc3a&j)CpUq_|X0jQ~;x7-~ z!kJ6Y0Ou?Zk7gbJEHak%CDu_E2Muw!liLdoWT~{PX`XSgP=UPB($B)x^{V;FH39Fc z1-d~gCcz@o{~IjaC~uTfw>cZ===2@G`3)WYEsn&%4FdzBhxfl&e!ufvWsIS*O!vsl zc)Tql3| z*3qL9{Z(J*>k@aywV>4*(|8J9185WCIWw7@VJ0|TW^)q@;XFTrpYX+{mNC9#E!i|-m#xqQ0xMR6uf@ssi&Sgi`S>c z4<7l&b7vvYAHa2lA8<_k7F0*96ajkNz%4=;%>xOE@LVL7=5MCwBvG>_{jlye6T$$KMU zgd+zAuDD|00RM#5mk%F2ID9$(7m?UVSyyRr-|OM8gd$G&B2GrcPD?C76GMaw z2pV2D_+n-xd4haS31>$4DyKx%9Dk7Iu?pQB>Ye*aF|70}ZY(HPNUi zRltd?;tWr~uk3VKE*91v!?N`F`HS)>-m^tRjkGB3im!^DC!B%n8-FPNrRHEw*A0z7 zgazyieC~>UTet4x9}>=!i1Pr^;5cgdIHs#B-R?@7g}v((ABQ`RoV$GQz5`KZ1y)wA zPIp(jX%?32WYmD?_U*m=+>vvLAEzn7^4DScI3__!JP+yH9yP~|ILE?IX4|9u>3;D$ zoW{Sq;sJ*3^gH|hi8dt+L2C0m*rrPvw`6Sefh!(}Z1)B}C-JmC>OwOMihxFnrOh?5 zUah<@qNGmMOTGij8skrsmYMhy{`yOlcu1 zmYa1a0iq_blf>!t`na7qBMchtPC~g}I7NhbP@^SgBhhON`Vpcd8m&$B4SOaItY%&aY!28mtqaT!7=^w?t_o+SWr4*;$7o-ZYhDOk zYB8lG<-1mno3o_fAFvyF%8garITFX}AJhZiKqM#GKDs2?nwbv3jE_p!1sKz)DF}cR z%Zs8Ib4ME?GlhBZTtVH(T~L(%qYDb(k9YkuJ^jbr?(p@xi}Q80?EgfL6AH6b`s8G; z(!1I5T%59p#e3nUU0>LXMXSjPnnO#7hIqOEfCXmk{5+4vWl9zc*^R(0XR`SG{{4H- zUH-%g@QTmFS#h;w6E%}QT1N*-2Fa0fwr4Oo#9=pO;sQ3r=>%r$O$W5{!iCF?j zB!AVO=c>aOL<;}nf?wAyZP?UM(OuNl(B81A-fZe9dOzo}3}>CoWBIQPEFty5My?f( z&~iBrL3^;ZG&?g+rB|!)OY$2Qe#mdd0kP@Gfs=vc@P$ecLRew9|Q$>G{e`|>? zXk}U#94Ck;e+w{yn$T|k*4D7MHcvqA?59W0iqD{k{_zp|*XcyrPY~O=7TbwuvZorG zF~qTiU;>btb7C8$4TqudK|z6ZOKHN;lFE9lMim915;=crx#GF8&w*GyqkyL}Yd1_wTy@ z%J+}|mA?M*Fub}~Tu)yMg_QV_RQ+8!p7p!*IDL)B=)$<4Mxa6lwvSqvbUsQ+f}m0Z zJ151bZup!R&f7Wh+B|NZW=;?drjaQov{~o7zV>X_r^Y+>w=UY%y0c;D=H7+rZOae0 zwEC+THwWlzKm4DqcPy*fxOma}swH&i-t@y6(^uCQm((pRD_ckid$<|TKJ?LV%5q{J zsU$bb*)R;iPI>9nFhw+|dTVqWiAp6&=Y!mmFO0@(CGp%G^hKBE$`-FeSPgyFO?76vic%Zwmu)DkyfsXL4rm5lKDR#j=bhf{_DiElu_WP^FiIU-(n&A=# z>0>t-fM^-bR6m$SvqsWM9+l`;wgA+L0C7kO6fxr=&Y+2lq+DtO`r;Ub(PVv+RwYxf zI%b_{`pK2Gtg;}}(2ocA{9!sabvAV@Y4JDugS9p1p=sJDqG_a7<%%d}`y{l6QiQS+ z;=N(u?fAil;9|(nugGCghJyg&x=FThg-Bsqj?si-RwHr608ZHBY@b{9@6dUwmJd zS<0k3{G`WxjD_om{B5drG6Rp-M-y+pYEt|qf@CHfr4hS1e1u+%JCQ@5i2hqj=B{af8@%UZjfIaw7#*)qNVxgQCb=J|7ya85l; z5)dzgij7HffRmI@q;#0Xd2|n66vQu2>^XC0&jhqiFdFmuIE;0xV$Vk{j?J9;2nEW7 zl>0YM6R8*LH!gk5!xCV~bBpkds4R3e;~H79rrlaL?RvN~bFxZ1&%|rt6OTyqs2}H% zFZMjrM$eQK)f#QjKll939XoeGJ1i2vikk{8_ul(? z0%Rj;g}33m(dR9=VJF$X5sr!n;Je}hLL zwIVp~=kVaHHgFyQkTw8piIb61O-2DCMd9Z^XRYz_HKYPw#qvsfsqW+&co6jXNURjm zo|-s=HWffS1@7My;Xfw`0;*`qf`l%vd(4M+B;;0vZfHLDgVg zWUaV4wID8zjLMZ_)<;W&sk)kw>gMW24RzSz07|Y7+*B>cpZB(A0eyc(&$TLvbMW5(9DUXKHV z>aN(@xa5#A{_?cKK5L!8xAy%7kOJfzOI6ycK?8PcWIq> zRZ|C5xh(1K9CLvw%Op8@Fb(Bba2m08{ z#X1`V2pd8e+r$B(d*qAwdhsN&P~WL?5;9c$*uPinM*|DDEP+)A_a1~vC>gA-87%qu zN&5V>m#>d>jKTCi%Fd;vp6$##L7)pOTxJyCKrrxt65(WVvfId@(B&#|d-?XSMjIV+ z%*&q7EfkS?(2UtMU6o;!k8UyY!k_FpMS-c-y31X~&e7t6(yE1Zoq=G%(Y z$V^PkS-ddAlAw)qWMo?wXyTmdl273@eT)7#(mID!lL>C$8OaB=sJbx}# z5f*`vs5R{PmnIIh0y@v=`I}%w&w~r;@GJD%Y)rnlRokj6(7KW9Ny`&UnAEwkukaq`Lo_g$-2ogE*)Yvt;*V?9?cZ9CH2i&+N`_mqwX0;6>cmuD@~P#gfET0nAW2_A9PPsM`{d9;qXO>i5PVa5-! zw1iQ^Ur`b$4RC)ex62tpkp!6{3KLRz%WTe*!na@f<~3WL+H!f*8ve*>F~;fA6+w}& zxLwO8+fMkki zE-q%DMVeUKrPf*d;@LlnXL(MUf54Y1vyD61o{7_#L4gepV;%yq zWF0^$jD)lF0PQ72vLoer)hK&rFjY37ynSYzt`vnI?FfP|qdz}&Vv)c8n$0Sk%@wp2 zEjv)zm!53$8gkUP+k*@LzG+i){n!_l8I4|dp(k({uDY_?WLenoi0rFQ%lJMn=3*9@ zJ|_8#QOdXUm#MoV_Vbl2Hp$NCpL*)Hr=PwJMi0IC;-TqZk;t}E$&*s{DaXu4-3IQX zr)<+fFQe}=)GMU@9otOF*)AeIGv(4Rvc(HF#{E}QV!4ma-W}(Cg-fxUxHpd7h0$jZ zzwp9g{vpYW(?S4wqlFZa&R}~%4!#{0fB+FrScIrGM9nNi1OyG6J}MO*K`d0GT2N6{ zFHap-WG(Wzuo-iT*Xhw~vSx*WW%)GI(;{{`Qp@qkt-J-IL68p?Ke2J+6B{=@F*SWm zqt89m)_%0O+JDc=cQuBR{msn>O5-%bnzL)x-o0kc-D`EK|IsIw`|JG;?XXGn^+bJ1 zWuP=Z{;L|o`F%frVEiJofLlcK$njuY8i2+GdL5NhI=b1rj^&`4B08cMbb4g+S}ppN zQi}7J2kf@9HIo-rP7RdWI(caxygXc1-uJ?Hfk(2XG8Zl8-p09AJgTx}HmBk_-~idD z4@gAxEPr?~viW9Yth99F{Nk`lMOxY+#w^oftczWk1ol8$`o6PnO; z^?*2p{ACDM7kb=9MQ%@__^mZOZv3UftAZXhnzso*LreJ?T7_0O(r0lRIY|lekzbxm z!v2P%lKF@>9yEF_+u|c}D5RsO7W1oC8&rZES9|6UDrd%&C|ojMRgf#HP|{ba+)A~e zKdJ^{MOif!K7_KuydM9qRK#^)cez-yHeWe4nhRvG4Ijkw3S#$E-7PjenGy&%sgB)E8Kp7Jq4qr$Kzcnw06v$uha} zkLH*wiwz4G7Ic*Px*XLDn|j+D3R|;#U8Rnt)m3nlIV~|OBLz=1WQvE(m!!Ci77xy| ze7J@Dfxb&}JI}e#U35RZMt^!SXPTLp#xB?? z-avmU*$0Q|8n}wSgLO^3ZloPVsf3X|hVQ>>AARRkm&x#YGV4Nca>d6?&y;4tPQby}fu_lJz@X5>wLOm$OmP9+r2i4%1RO>Igsqw*LTc zKcBasBU|7iH|7Z2m&1nnJDjx)()_KIE$am=g%u0vLQn8!*#j8vKc;Iaxd5#I-Qr>R z{&NzsfaHg)y=xz4hzq)88ai%%c;bgY<14^R%4T z^h$P=5pG8rWjO^{l#jV_Pi4t4(s8If;=70&wb|KTZ}!7@W#e}`fxo?x7e6;BTJiaN zguTR}UC;ARPvY&na28W|>@N9?uvm&^u8$})6{Cz9%bXC#l`>oBmLVV>!ZNu+0`vFc zJ)J+6NsQi!Utli=yy!%!+l7v2?o#Qw6x36)%M9vGb> zkrxebca7Yi$yxn@i2m%wGWTD^{0b31zj(V>V4drQ6WHz)Z+FAoc4s|%YMy6P(T`5T#S6upd98mQWjg4cjV`WpqWl1|BS6 z&QuNy>cCq2*`;Zt^tEp@dKeI=&mm41?`t8j^Lswy&xeL~9=-M`UDMHl2$7g=sd-!2 z3~PaJx1~#^InLV>E<<{5QfPjyM9*u(V`-s7q3e0h>09MA9^=5l0KmS^$UtbEQh`J3684bz@bkI=-|`h|7D3$OTDdZ2iR zobrz`!x=`)uG(;tKN*LIgd4d&ikTS`ctT2+C$WA06NyPlOef8CxmXNVK{@O!9YoYb z;PCb2C6yJ3hRHnC`8630L1%SHXv8hA{f>eOqj?%#8M>LiM@-}<$tTHlA)h44dh1Xe zlXy|`uX-=Vc3-0Nx-Wg4XG%(sOV5IC+E9^|mxX_%nfV`dWqL|{yw$v@J3SSDn;N^= z{L7@PLZ^glaQnV$7CGXfHAcd$=*er;byeNMg?V?(P`|LGSI8*aNnG z4Ec{!C?fIUcVj%K$J{tA>CP}IXm}a2gU`Rp^?GyDiv}F@={$?gZZ>(Buao%bSKgmCYfxvM?m#Y@GkgjwKA2Ac8L44Pp;%qaeq`GZw zc5{xSxkqD8GuyHK!BA$Xh3H5sspswcSRO6b8_69_k$R)u(YS`^aE0GDD#;~{#Y|_1 z-K8FWwmdo0X0Ir7Wc4Q&7W6E7(-604fz7(HMqOktt|SDer$d?IA4wib2~&0fkCl+9 zQ46F!*4U+x6DvJ@!lnL z2wvs)tjfJ{x(43k_sq(@M?;x#JJI32(ir8klzWHi1pJb|jrS6id(Yv$LqY=HOIGeF zda5>6xpxENSI+NcD)$s!SnE>mEkj(INgm!SQ|>)Rd*FVd3GZbq_cqg&@JIR{-m``8 zp+5EZ&_UrSXtfD=YsG(TcD=ss#v348w#ltQ29_bJ&6?m>FRwgpUxG6a_nk zuw3D8ge8YzFjMcN&Wv7?pIr}m#m7(_dKhk*@7xm) zM~XZM%RMIcz%2?7dYAS@@E|baUD#72UJZW8>JndPZA|Ns4}D9ZF=L!E{&RL}`oSrI ze*7iGu^wr;k<;?hxj2fu=(#sb@+nuSm&IO5+CqOF@fp2a<{v@)aCVY zeqN66xOb6nB$NCLzu%HcQUP;{iF&s=#Y>uMs!Ltg%#@VG3~SMwb>$`fwmhpZD?KZ& zIh{~$57|TCl=9SEq>RFCgt_4$=tTp zk!=&!GPV_NTd@*Eww=t|mW>41@UFo@`s1BDtE*@9e{4H}1f@n75a80uIySC0o~2|S z@rA`4RU{aedt;9DvQE8PVDnU1tzOqf@lb1eR#tjd6CYDar=!0mCNM~Qaf}61Y?rh8}5E~u@ft1!Dyd}c;%V^UIFoGGmaDGZV>N}rj%-;F(1*kV`(ex{#~$5A>M z^3jh;67#6jNjj-EmQL#8$MR;YqZ+OFEqCgIbYqsIEWg~FL-(g-CM3m|W)!%r#qnIn zX+%D_f&Pi}4mrZ@0?sq|p38ZiR*F~x67@T5KG}y>QseurS=Hn*f}ZE`kV!cUbJI;(c;95T(t&i)k-^KeAS*D zfz{6JZ0BkiSxkre7u&sF`{I5HrxLVVp&UlcWs8}JDQYe@`11Er>4OoJmH^Xq4+a2O7Zbu6WYaXF17Ob3jmbDj&Nq} zK8o#S#J0qYJQ=pd$aWaXQt1@^Ba0W~06TJW9INR){nGGqdFKuCx6n!$oL838%d*rP zaH)75430Bh@H+5?mcp3})%o~3`ajb_IK%2pKNR{_C`9)}zf<*+T(xdOTrf`eOm}np zd`oDNK;~^9h+CWNuPOIAsuSnwp3*zJ(mUn#-%YpC-rRiH25U#@Tc2%nyOwtG*t**wpByD> z#v8-9({Qpn1!XOwoXk`8w zm;VQ7t2(jh^0zi$9tue^l`u&h+Rcg`_>^P^KE>_8G0IHNTV}6ZMx)(^c=HmM%laL{ zPYK(VHnv2!!DL6WT&Th_8)aO6K-NlS)<%>GeHc+@a-K5Z6Z(`g+sJ3hpj2isvdrg% z-K>m)&!?p_pXOy09au!@k=Xh%hg}&P#&yf1(RwbzPN_5qI~Gfi$Nv8SVaH>^u-^=J zRV*0x_f3Rd9osgbNoXADwCqZ?NgJ8lELD(x=ZGn*({+w#^=N?|GN- zbF%LdLa!E%5(lir8-jK*-OBD072aRZ?vt;}_ebU27Td_LNsjc4xq(h4fzOEUV!u9p z`csdwdrLy6$qU3XZ+VSW{)HQF+;kQB{{jEkU;F?70RR912QxGNG+pOt}uZP}mh z|AuV+KoJzcJ_7)e{03=w0nOP3Y#g~4$MK)-DPyi_uPL{IO_`aQasPMa_L!NOnVFfH znVFfnc+AW<|F5mdYL#?Xdy*QRq>rA*_B?yu#8oG;(^V-+rY&IqiGQsP(GbA?t+f46 zsa)JJrR!X)w3{qLI}=0yLhikIJvvAw!NIKOl**|)Dw#7*#>Z@C3VGhpNa9p8CH@NU z<0AY{pD+i^i(erQ^K*zzlfJdKef(X`w=;#8!wxs#Ljw($?{ey-v7QfHEn z>lQ7}x}Krbe?hd1QuYI-J%4Ri(9Y)|wX0&fYJ!jXxJH`k`jU4$MY*_Q<`klH4#oM| zFE|Ist5tROIXQbp{6j%5Rz(f`%=vQ`)@hA)wIdp(NuEEmbvEanoUhb+v$baCJ(qoy zGHaMeEwUrPIU`on!N=-sJI-DrI*YUNB;eZdj6-}}w`g{VNX}GW4YmixKj-4#)A|(M zT9Yf%ltS2R)xCyoRbCt1TEO1MK4z;^PIst_JvE70qF0G~)4x7-i@)*A;i_*R;5wJ5 zal58KAjU5Sv`tS9gpb2b&-hn-f>XG5#2<*`z?}FoVh=yZZW8WM(*M2bA77r$p1~St zkl)86$(_lcw66e>JjD1zGdW%xm1qjs8{k^=Y{cr^Ct24gtJ8l$R7vFLB+<#-tSN~K z5aZ92>%p`?v@KLz#gu7+k9pn6y))Iq+^+iOK{W|6BmO5u*qb%6AP?riSY8{)zqxB= zsQ;ff-4YH#beL@`fuXO!a^RHm-(P|%b2^SKj`Fz+)J`&Hi;STs}K=? z=!SC*_LNg}N!IlXD*Z2Tj}Q-JKL~wC5VK%>5`mOTs)T=UiFq|wlo#itAP?lgSYF4( zf4NW9vO2r1tX&xYT#&IUtAR6J8{ADA>(w#TevCS{KZK=t5&*42PH4m$A70yt% zq}|6n9KV-6hQ?X*`el!0pEZAmqGo`-Gq>o>5Rv?xmhxWmD7eOt=Wu6!QRABI^%_@@ ziK?j1T%dO5dbM^PRo|}GeET`(CeoVkMyr{2K1=vJw@Yp!nW70eriKgb0$H>t^I^!365&8MAm zztg6sUNl~juN}4O6`9$QFHb)J-R?mqQl6|H?EtZBIY*q_hoY#Jg}3_uLrT)9f7D8&bcm z;(t6hR~_kdc0YBtkFbyD0edEv;yUWLn7${;_X5``_BRK!)YR}i;Tx-8e2Kj=e$5@t z_#Wy=`%8O_y13iYs~GfBG2@tO-(}HJ6ZQ$;;YzG?cE}xuPfXdBK1R0FH=XpK{Ivq z^*S@bb0)P4!rGR#sEKW;=60SUyD9IcpUQpBsc~ob9DRo}_AqnqjxV)$(0`PM+a9ca zzuJd2P5i69Mk6u~VeZy4;eGLJQ8CZAKXrIkBWRC|25O{TsL|}Nf!mikO~AfGoh>?Mz*DL1~C^9f+OP*RwNuk25vE^wJ=+6>d`#`wIDw ziC5rFGfrd7epsTNs`_-JD$JIe%KV1rXbnI!vy0MbX7(lS$NlGP6iUnyT8a{L81uZJ zB=?!*-@T7jeda9YCu3o+KLlMuO!jYws0<}$W0j%A+^N3$glCwcUMMx&sTWF36QwfG z*OH&rmKu~ZXLE8Ek!v_PM<|oi?4Z`@z&@od{GQO3_DPTw{;tFC>U?BQN%&p-9n^M! zI+#`Q<@S1Ya4!7aXM$Zto(u3DeJ3mJj#h`dR}r`1x<37Hs9P9+mvj1%dPOT}uZ(~2 zwYT%wJ9W47H7c=_v%F4E-@dwhqzF~vac~LYDE3s;T_zh zrnaG4x+0~#sFfmfnL3AeaVG{U9lXoD+0+MaIrAP>+UJNK;CZ&B_AS-TbW{(2PqNMe zpM!XlU0}KsU)2NZru(3Ox}rV$pe+tbqLR2T4ocdC@CF)XX@>=gVzkcEwwmpvzh6r3 zIT8=zWb{ws#*F`+jJHKy>93QBN}&i*V7Nb(|+zfm>$$B$Ey8LDOBZyDPuGAT_pT{PwY43o+l0001Z0SwUt(4aRI z0Kiwf{cW?hZQHhSwr$(CZS`#1u5EWSvmcX(Bn;ze0H(2)qx>ClLJn8+FmF?jZj56s zM=|fj6fWj&UZxuD7{4scq+|Jun zqaDLA|I8e&=3)FlYZQyvi8yB`a6Y&5Je6q0AZD?V&m+zWGPsy>5ee7RDIzh2i@BSZsfIjB8C=f&yiP4TF^Wa(M6Tr1Dd2jBp}&+8Zsuu5 zu?X{1^_7;w#oW!yG@=)i&_nvgbi@8-1Q}e;{k%>s)RCFM`P|O)*pI9rgUh*}_i02g zCb5!(*yHR3&gXWl&v~5pX+$q3v66$BpPRt>n4cGHM9%ymgUh*}y%7b^qu)YjR&+Kc z+|1K_Of&j1Eu#2s>d}p*?8Uj27H~a}^FEDmE@k$({9)Q*|Ia_2LCj(!YP#TVUZxuD z7{)xd@^!?8C-Xl8^`M(c6vqKHm~d^|wr$(?Zf#rf7gk#{EFYj@jksZr2kA+2qM5n( zk6&gp|LJ6aY4mw$Is3WJd(?J#J(qb+6z)2*nbSPxH(BWU=yuNYoG|kEPbULR0%W9o(b5@Y1Df*U_Xyh z`?=FR<~RB{f1LY#N8T>3<}kPUO%^4z(!)6FxwM$wT;?@V6rsP%C3yeJcGPq=U^AzA zPaN`cEe(6TejoSW2-wVN9`lYA;tIe(EQ*EjN7=)<@3)vPe!ExuW#2E`vyl#&Gw`HOc;hgjkC zKLhpbAV(Aj0C>wSW2=kJE=CvIKHKijw$q)>?(7T7E%#5!SA64{_vZb8+WKtmz699A zH69T`0Zk0EN*FQwx`kuh;1y!{?G^Ul4{!?q|HFFy+`%dC@QxJ9FsBG(NBZxmXT(s& zIGgzA=q()M2CqnH!5o7=|}aA3I%a+qP}nwslmdi}nIe7xuAp3AvDbDc)u^Gyk)*$*9IKwuP8~!7r$_ z;D}&kgMYAig%6O$l7K77Vwrj?{@~0i`)kdZh60H@{D42PZVeL;p!W@bq=RfWv(b!c zD3BndE&ACe-<@bM>n^kI{qsjLxGTN~X-c;)`j@5nRb7x!7ZZfesu|450wr$(CZEIrNb~3ST+qN^Y zb92r;@2z_Ogj=;g^xm~q`~UVCs%vDKCv!HGeYdb6+SsdqsU^m5Pw?`!o`F@k^r|Ekw-o?aWQtJ*URVPdz3 z;}IalYb?;Wb$@O*2+-Q95)Qj&unoc>*V1m+>|?M(64uW!JlaR0lgLf+9-!NZ@Ctyw z3mwH-Y!C?foy%VjPkaQf@hlnQyNdBe<&@7xxZ~^r|2jE$ql>Y$N>CyzSzg2yRkB06sd#16CWFXm8>47 zSh5dC92_AmLh4K%Cd7*k$X1~G3+i2HEr@@5d7~v4ZZlzk?;0i_?ZK$Cvz@liHjI7y zce7HX!2rjXzT`qi$`GCPS%%(X!h8TA(2~p@tix;osh0msA714S_=aktAA9C5LWe3&0Puz%J2E** zE~0d5A5s@zmW1SN;Li;|Z=)oP9&kK9+5;akK^l?TK=d2gUjebfB2qg*tUF#sD9Al8 zl$-+u=pE8o!6J5DWZ0DTX4T9gb|MHLU?a{1R?+QYDNX?b&kSp ztY-du3;bGuSd70rfjlbT_ClC-6MaS-zjfumrbuM@A3=?}+ZWp2>EfhcZw5QrYagr( zY}{4_WJ$9HSi0e1`i$g8D7)cYzwZN|9F*V;)q|V7xWjgGMLTyN%nTT0eptdKr~|9} zj_aZ540CmNM|%5yUw6_G+2W;2og%~OW#)>E^fk6)y*9ku{wZaO61{_!J^c1@=Q7aU zi*a{H zPIbe8zaOm+mWgcs44v6O$%Sh^KpH0kPP&0>zJM{rm|@5kYWd7DcLKLUtRMoex${23 z0^fVA-l>+c88pGZbX@Is?cNL4!sz>xW%ol2EJl>Fp|}+83EkG8Qv&*?lPQpjD9O6- zJZ?;N_eJbyLR_Z<S&RW8>+adp#LN&WcC2&-5y^x~fNWxb=egB|`T3ywO<3*iQS+3>|at6r!WN&rrJ>J)UU@m~K3hdKSVVe}|J6oU+AOr+u_ zP z(-%mUeJm}eQ)nA8SI1ZW&Ufjl6TshK9UU=gM=?7;?(1^{v}acPXy3i%p%|#E!y5*; zB^gWkij6C3q26}jR8sNH2eIz!=e}SU`tuj`ae!w2F&oRY%M`LpYOa5**N3Xx{vv(a z#%>xqp_y{=de_RL!4vSoQ zhWga+ra^ZNRv*>`1Y>w;{<h+oM*hDojVwG!fuy~I<2I?70cAc~ z)8oGT)J*kT7IscN%Wa0fqjn|SL7AFFvu|d}1p!Ir3j_VEm%g|}f&7b*b6F~gUO6fA z=A(+f@JDlkd$@HP;>Sj)=aXYr3h284&6@@Q=xd!9jFAHX^Y*yoKES>Z3K!<<#%jTq zzg!?Vb4;Iui{B5i;L_(x{>3PU0B{JB2lA_F!d_PCfVOPUs%^3kYGl4#U9PXXnP5;c zT)#>=Sl>)*c7NXH#oWdxV+_S9mw(&m;qui8@Zp)}&!$U><4ioR@O-5S_dfac!qufX zMQm$tJ0-DIDgf;u1JcI1Yaz|T2F zZ3*TvEwdwYK+PxH>TnQMoZa2R`%)i{XqWNb>5NDRkO2wY3{`eax3_JILb$_1`0y^= zVaI~>!$y&h+(nxyoz!ZNN%j|ChZ|RkyEyw)g%RA9y!ns%6ye(A+rJCMrh_=hpiKL| zNiZ#uj1?Mzu8R&!Qb#QKze>>AEfP}ud7@F~BHGni)7U|^j%gm{dDGd2R)W{yELR5f z8J&) zlH0w={F&~n-dRj)_XwvdyryIWjP#4kuWqv;CG2z_Y-~^jN52-ignb%al(W7nn=`Py zY?)Z4Ew;Qc>6^kjABaqfFBu<&-((N4kZp%e?#u3|x7ua$c{gR z%tM%~QJ97KYMiUckop;&~+mG$-C7$@YBd5$D_cvAWk~>fBFsaiB z2(i=TbzVsQuCUJ^{n28eI6F`Wzu@?gl6yKv{{Z}9?5MAMuxR-re^a39Lvs?a%);}Z z0JlBom}r{%bIE~p!h!R3!Wk3T7@}&_0y{iA z3;ej92?Czr?}56y0l$5z4}|E84WNY8gM)Ajc;4R85>Unw1jguoZ{AI}b1gyFdd=IN zgSonL(!#pJ((TuN%Oi}5_St1^XQ>;&7N_82=Ae%f+}Ky7hHxDqgg7)CWOK2PVy&Y# z6(R&_OdX=v8BhRQL6scNL%U-`A0Nm=-!@?XX^497U^7^+M$4Z&wMdq%i728E^5udc zNC-Z7dm~8Y_9P`plg+PN12D?P3RD|p9(i~aL57x#l9Ad+eA>C@`8Kk^Sar_`jX%_M z{)s?9qyou&M9MEIZI0tn&;Og%*E_Cp_Ncz2uJ(REpe%-QT( zR0#VoM<>n)VS(VQV7E}sNYhsT`&ThK8!Hqn5Tc)r8u<)OcEA-|Nxr8`>8Yd@(&_lc z%#7-4K}pSrSEa4pkkIz~OK6vH7M*v7Bg!to2M!}G+J>!xee;h+Mce*rNZaw6%RT9o zbtRpnwdpJ6)1##B{?_IxHdk9^*UO#UHbZlDk?q~Z{)KDFLLKfeSkO1c*Cutg;qjv| z#}-Qr%!4>2S>%3f-;ZP?yQ!E3b*R}yB#OTNp9 zg3CLx95rK-_Wg=*-bdX_hWz>QlZ=4L^Bh>^qoIDtRX)%xe>igN_e^lqu%ZFXL$ z+Jy`?NDw_nTcW5t-1paBMLaVNZ~<0x@kG(mWpuohcf%`L$@hGUvCdGDP|~?C=`X6c zwNhyLkLAy~L*Sr=IL364kfv2j>R(r<`<;N!K~++`Q0=dg+G+gGneH&8U_3LAj-ARW zg}?G}ws9@uuOB8}qG0iRH@2?1!td=aF1FePS>ub{oYvODq!ijduLIK0eDXStAgqFH zt%r$Ah~aSbA{GLBmjh_>t_gU2r6+t#QrMnq92cwTAy$ z)m?J1yskK3a4<^D@pey*6n}~7(!~{$kdEh`lOzaGninei1++;JLMsO4qZYIXB+ej7 zDEyvFlu!M`QGS@1AW!x&Lnllj3r0C6McP@!pj;}!Tt1#p!CWd%qg}uP9+?U-oP}c; zS&;rSLKdoZJ2LzmuAL#VY?{q(uP+Ls=FiP8IbSTtSaG$Dylit>4JXr#D%Kfol$jJt z`kWLyQ%SIcxj5C~Y&uIr5$@$FpD4#^+U+SdmG+4QYukKa_I*C9H)?|P(@DkKeE~0F zpHLX3Oe7l=w-FEs=73%ZAWcS14M5G3~ z&hR~3Aj%6_T@bzI95j1rR4C7U~LlPCGf7Y-ptLnGFv915C zq8WtmhgLPM+Jt7gAYI#uvdzgyllen7M(1tSF|Ay(4J#gll5>oX%Ggte%Q&_%ia8Y5 zXG;HZ%sl5hZtn@E-9!3COSYKHO>18^u5|^i+V)#y&dhP2geREgF71O2JbK{)nX?`Dgjq8LE0fi{5*(mlDDaK=BKl`SzWaPHNlxrMi`tSOk z&P{$whg7rb$Yc3(q}wL;);$_~gXcP@lSc~e_3W-U{_~6|&ttf(_mQLS^PFneW0dVE z>9lLtQy~6miQlph(S>RE^P;WK6GZUmL0b2_EFu@skp8!POnjOwHd%W%{=5BZvL^o~ zQh#m*gY|(R`HS&)A@-zn-8R~KopWx#^~U(z)|=%=5EiQ$L=acI?MV{k2_Z`ol^MlL z5*8^bND@~$&5aWjNHL5PRapHQCoIu&7$>grx~0m^6@aG7FE#Ly*McHVQqaIOPEynX z`>Cv;{!>|5Q5%kVQ9%>ec~Map1THWjP=IMp4Mm!HUJHh%aZUrh8mnqKPdc-1IE`DoZa7bSBXHf17|L=zOgPeY+>cq>c05dZ;(OhXns&cVUVq+{ zbiZHXf4xqB2?Rr-BME6rRF;z`O;VOuW?o#BQ>1BJlvm|`V4jg9 zj$)owVw`N8QJ|`7oK@kxbe@qX&vKqsX5D<4QKaj9m{sNdfCJ1B1j5lT0Q#cUh90P5di;n=fZkw41&X}?Z+T2pJ45uJ-m0CWtf;D6;yAaioh8e#u3KbT zzpS07ZNIEr=6S=ln;{IvwO^ng&a#{PRgz`D#D1)8H%pqLZNJF8ylFR2)4XZF%>BfD zGeaE1{da+Jy7Oj^s;2Yr66dw|%`AD2_uoaZ{HbuCj{sOW|jRuSPYQYlPO^^GtdE1^`!hVrREJmBY!e8?y|4)#*-yer{ zzn}sjsM){Q+X1)_y2Kul(@0yyZ4y@NEWYry#q!$cwLB*p{YZwF= zQ#H*>Bm9~(8u^prtz=e!@7%PmU!v`@Zn$WO_Y_3VeP}-Iw&a-o6oB4&U|i$2XsPoQ z!rFOgeGTYuPlUR5&(Zd}^GEPLFwA*gFy(m)rt=<@(tR6huDs2<{@_Eoc9V_Xr8WWW zR~v;+uFojD(Cffg9|GrnNpr3=F40vJgj4=sii$2wXO{C-X!}HzCo(L(G^(vMCd4eV z*vtgAaY7&ME^YWnv8ZGNL)!6dj=9s29|lIC!Ogc|oaOohK?AM4jYGDyE4p^J$t+E& zLa-3pAFPBcnoeoAI32D%ZsZED@$t&DoSeR z7gUtk>X{i?8DK@M4C&$+{2X5qM&_*x-(DGBo7mvxzwtx-Cy|T#+J3dkdf#f@&0;-3 zSTeavtaoF&u>R`YwuFk*!Ou?IMfIn0aM{$wWRv^0TBytAnbdb1 z*%@Guo*i)9W(s|LAQ(MRDZjM3Cme|PFuWyhDo<6qW^GI3&2q~OUXxXq&FZs5{q65s zB_>)K1N89+7k9U(x8fHzs_HiHPA!&8JWQ~1ttH(b-u~9A*SktU%#{K~(ybEMhO5r{ zNd>P&KREahFbK}|iccShn1M|I;nXz2yJ$#&+6GkUHv!~vL;kA8;L(Y$lZYgm=?rby zt26c+=&3FrMccYCR4r>?X?i2N=izsSNokl^vw$qaOH4qokIAI`h!(Qy-G_(c;tK1! z3>sV4{#r`Eku%YWsF_zKUPfpcUdC;0Mh#w2kdwpMZZnoYHc4~ys0b*Xt@|>DlAjf_@EMv_SZX5ncF6jiqWsR!jD5Q_Ir|39vC+lp~{Yi*53 zH-D6GU0lGk^+!IsoEV(s63qd&ZaBc8AmBoHErbjf6Ney{nK}_QOU5 z91ZCYQwd-uIHSpaR!Hm!*m&?u$751>w_-ek&C8v&q?Y$PjwndtS=jWX>yFVJecZi# z-2?^-=gjoK0H9!HPcOapNFN$V*m5LlN9-c>3nGI03(g&Fn2G`KZ_7&B62(l(#=8!G ze1)lXWKWL#$t`79;nT)W2AMniF#2#v^^h@d={Bp`%%;eo@)c<4M%a2SZ`XRVGDeBu zYeLP1-e20y@QUG3Xn@g?P56^&PFTa;Nu;%;czn^fmkjn^&VdL+W7H%iO-!=?dI%Ic zxRDzw0OAxr9WB@F1L9%_PZXmVFK!TKBl!zyWCL+XxF4!6#_bZ1W`YuZGKWa4-q1>~ zjZZxtzI;wTKZH0@CO4rFjaSy89}Jdm;pe{ixs0Fp+I(a1-T@Dd#m}@BDiTS0cp%!j z2(b3xi?s;;qyX^Z9vlb(^!G5HCGU!%-J%eMa?c_q*2+W$PjLxzcS>>XxD$H`y*(Bd0$7V`XgX_hY|?h^2bt)ORXW zrfRJ}OqEE#TH$8J65mG{s&a}` zK~_xtZHKhBug$Y2LryknaZ^E-XGU1iu^qdt1X+!+Tfw@hTT?~$d!i!ILp=3TH5xvk z3UL42sq6e6fa*y*15tdOQLTMB^~joTKAk=qN}irDbVK2v#8K-4t%sLyDjGSBP?!}f zau{&jgRHj68OiB=7w1s2Pp2~@15uC#Uzw%wz`xc0J%%TuCP!qgOu!=Vbzlu@ zy6>r1@j<;|{y5L&7QgzC;_0z4OJ(v=dsC-#)hmrmQhA)Nn?HaqLE zMM#Ce15hs48BFZB6$E3GCL6HI!%*o_Qo^T64#t8vY;7v?OcdaXM(hhi9HPUh)9bK) zrv(A9EAry=gB@fa+IvJ8VuAfE&oD&%aUyMxfP)_leXxFAAA}kCMBNf_;!HmxTl#Vs zU5kcV`NVBx#)xa#DlzmTeFhG^^M!UJ^!IO{vI1*zaQeg-$sT-~pM091U8o_I2?$|k z;l}ZNGIs=q-l}sQ9tT=}kIClZl*sk%`h1{ktF)wY!GY|GbzHf}te|4j>GX*F3Oo<) zJz(NAy;`PQOm08nIWm@M6fl(}ZQ1NP4K>>4O1$&$a(V8b9G!!Ew*jw(D8N?DnX_T< z^Ba3wxIF!KTu{?EC1SIKusVhyK5K)9mID5T};ckaR% zki_~1<-iE{)Iw%lP-R>ZbWM8B(liEjnZ8aCfEU+?VEiR9^v(2llEGWVSf0$XWQh@$udjRB zKh!21r$voi?mtUQB#IdeC_2%Er5iCqU;pANoT*31XlAD*qdfCWcm`GrDq~E_4QX3V0Ysl?oC$B%5t>hB)QURIP=sFIMHv6GZ78w*?YmkJc z^t7ssJ53%Omwp_@wr8=mCzL4qlV$;$j#w1CFBvBHYk;f%B%9jPW!vp{kiWNlgri|+ zH2A>1xK7$dNUiY-#->;DeK$d64D!+tmCsi0iL`RpYCL%{GpL7}Ba?#?e449S90V?I z25HZ2WrBNMpS#+s?{TpG{o$ynVjA`jeUb?~ptLRU^ME`A>?vvm?C~_Jax+NMOwtBw zW^PI3pxrDA-Iv6A2mDwkGgA_I!}ZHQ0@?@0qx2%{;L%G#aD-ai>M~85tz25|%7J)W zpSSm@%T}_=@$+9d^?mmiQiHQ&Lf(9T!j%oZupMTq=$n?ZEZZF~<3W>0R}wB7Uo2LW z=pB@_K7t>DRewam*@?-F_K8yS_a~X=S`~yDRJch=JPTJ-kwcJ+l9P{({S@Y54Vqn% zlCjCuVrS=UEv|G@I8byDY$pal#e1;gW(kZPBnvO0p|}&I6gZK^OSj!l-g*?98)uXG z*2`}deK$T6E+ZB;hr*UOYk*zePResB%2Abpmx-2X1kP> z#!pgCZ=oWe7bQ&-@ilxXsXXnLZ;(TWa1ft0`t+jDGPjeS?BC1ade{3S&JA(*5hgQ2 z90Ag49@))RaKN$u~_P@PDUD_s8);^MsD zx?5m;an(*ald>s#ekiAd&dfCKeIl?-(5R9t4sW&0V z?bEQYF^zLhz)E+p)JMpAAub~S})(+8w(ZDUeV?X){)^yM{pZ^0q1;glf0 zeWgLZq_XZIumzcupRS?&HJz-z(-Q}x zkIKV`R&4-YXa5WKiFb?)vpd;G9m(56`w$Io`rOuE4^G4BBnJGv9v#5I`kX17TBm1h zizm6ykxQie%}+4^F7$qcK4`_vv}BL z0=~bF12(l*uiyWC1(t*BxB$kfHw1)z8}8q$`(5F9Ez$kC!ZDasE}6sTGx|M2VA$|l z!^Zzn2k$H=0KL8dIEd`KSuCfO*v{LLE~=K#1NW!bfw`|&Dc5wD<&L&*KSnW(bo1jl zp0Dp))N=501Sk?yeh@vD%JOfKBns(1DeZIQDKj=WI{jpsfT0;PEbTs}sA74N_yjXS z1EFwprc99;F)ZN%aq1EzrsM$@EEz!?+^VfMSazp1UAS7?sDP zI;U#ZYJ|4^o^Y5adW?pX8T|cx5Rr-R4?Wx{hG4mvpkj%{Sjlkeiv;8JgkfFYq<1%> z^Nbumqc<4(jZ1!ISbsu)ONny&O*?dH-eb@k4o-P9a@*q%7xeoO;N_)bZT|Dj&bf_4SG&5J3HO-UR`sdk z`a^oYS39dlMm444d~yHG+-Uq+v}>Kn?tM9oTH`0 zm(x+FhrJSsG=H|XO@*mk=oHyr0<>V4sY6JM0~1TSKysiw&vH~!s$!QpUu3BiOWVLb zsrpT*ushX*!TQO51xTDC zK3Gj0b6#^`QNq1n2fwQspuBo_B01b7aW{kKbfIVYF=PgzY4W9=!W{D@@56ZL2|@e0#E|<1@u$pAjv@ogK|?5VV`J2TAsErQK$6mzys?MIRg7I6Q}wBmMV!5 zwO!bdZSwp`sDu}Es2{yE_^=J?!ph{qG{LNO;OAO>O=kDitEjA0YhL5whi6MCtbu#7Of6S=9FsEmPm zDVLMsSEZLhZJRXGlSB_})w-Y-^e)p=`RLk$s{2;2^1DsctdR zJQ>?lz$^|d4yUNAb9uLVmq{Gq=2zIazBuHl(hri_PZoYX$S+nQ7-zH)iVVaaYUVHD zX1Gu5Uuc*2*S(nGzSzt!L&2Ce_UjHPD|dC`IP*YPBktc*1QUz>aiok>IhZJW)({^v zVa?Z9ks7(Tl)8>^TS|K*#6jv?(tI1xyQj#Qj=$BWl6=cAyL}FK^rX@qR_~>vK65nS z+W^@5dXK=o{Cd?WGLGYKynGSMz82glP1w^N@W_YSpO+=VS5_Vt9vU8TP_f+m-LlXU z9Y)Sg^eMH$&`nYuPH1NnY-sSd&Cp_Pm(tjqO0fp1`y?|iD6kmto6Z2ceDZvRvt|)h zcRN|)B~7Fp-kzImY;nPB&p`@x7^y2^=Ba=Crc3b)Z;FxC#BNxqb!aEK_wuxwI%mId z;c1M@cgbvBD6}Qr$T*?Y`(+88lXjLId?2=Ek*zr#?;p~xFX`k7YG^AYfE!f{vV#Xu z&!3Xz48wef3jHu2g;_m0yN8R z*|sL(6$Df32sZdZ?#4642RIO`8KrA~78X3!-eL<^@R&<0CzPi@qw7+AiyOu|V|Vei z<2-TU+I(g1t)7(?;i0-RefBipBvVNOA;%|@QMsgiL@CK<1EbA{vW+D8IwYW}i`kgM za4UyP7Q7i257SHLD!1!6xtBO_S~dc^>$PB1E-a+41AWDjLQRkm3-bQ?N?BPtd+5zu zX9T-XFm3e3+qv>KF#W^+5eBM&wu4hUX`m!9Gh6)Y2Y<#B?zf8#7zp_53kc!6{*eHE z0;CT-1iY9V7FJ3D7WV5hRp$MxukikB*q0F;3et!JI6<%$;|N5bSdch@TW;X|OBEEK zWjr3x_%>7WBkg z8L_+U@cu*(CF%}51PhG>M;0qpX;ZU77R=yp&>z;+ClDkD{qEEgJ4vPkUggGCXgAQp zEk82MC8b(Mnj6b8)VC$tz_9=cPvgdx@7JD1qDEQ=kqN9TMA$B5soq>r&dTsBvIadf za1c{*7~Py}+MqT59+dkBZydeTn-NR~M1bCY1W2D*1B1@Eq*NwKbn`C>xdnCp1WJ&5 zcLOa{?{Wi4a;;p_Yz6bY9Ya=~J3EayDj=D(1;>IU37RYq^=B7>z1@Y9P*eyZ>I z)ont-;@m0f7o+r7?qV#T7)wCnDRBpfxZk)89b0@KxG86|BIL&;6Ct6w;+ORt9{v(L zu~cxW#NK$W+fqF>RfdXoxDx7n7LaKXI6isN5R^Do39w~hcxmXhYK?}0h*I!UdRl2( zn6%%2OisWjF>3%a+hI0DYMswy9m7n) zGfp4G!ZJ-;`W+O51$cU9nq-ORc%H}PBaPXUCC*=_6zj;zY(4i7h1LK;nHUNu<8 z#3x4&+I#oh9sQ*jLDE;A&(n0X)`js^kJ)FU=jAoV)UqzL#G zOG)H-wAx3%lTTyc7^1|O(q{r#phu^Vl;azWHHQ!{knqjKH#PrMdPHI9$S3$ zd>YxDw#=}ZYI zG^$LZP86?J988rnCV|-+PR1%<==+wl(67+|DGROzWIpcbO?!Zne|qWo0GuZk?2h<~1bP)#=X%O;rRL)heFYEWV?Jbo-C$?wPI{j*Yu=XI zFyumOHPZ|ltwK-^|ItV0cv_6T))@{5U1{O*e7xkx`#B{p4Ks7_I~~>Lr>`}=;okKM zig->r@!MX|2hTd?PpT`wB;Fb8MQ5WN^j4?L097G=Zr?}lUb>F8KGFLz-JAkn!P82O zpZN1HRei?D*QvreCm|0(ug|X2&T)%;sGxH9%{!8MW059cE$x7UmT|pFoTZxhAPTp(nm?$}xi7`;z^tdQJ;H4nB0OIphsrkV3OnM>U6C$L?S|w&O z2W1NKqmJe7aU~kLcQZs;-+e3^rAjn*Cv1Aldq6BRp_ah#R&q~Ktmgcf;8ya1*F9=z zXQM|HFCDTiWDm+7Pr01%;(bTQ*q&LC-!Y(k3Jjt?2PRXN(FA!BIR}BQ za14QOTUOq)5Hg`_+U!XW(azYmy$=qas+?s(+8BO}l{%E3GO=TXAFc;AQ(IIDsFNih zXNs(N)j2j*CO3Ld5Rv`=|NsC0|NsC0|Nq}lGLfxH2AH%3U-2`ye<3jEoCDs8BOOgq zOe|1RX2CRrGBM^wS=CLNqo7(URc+sCx=#0S9}h5N8;(%h(n6@l6A!0wmqe6lz(2nd{JbC(hZqcDNf^J zECV>)Uzyhp@qssG>d-+lzAb4Z3I|7WG>J~g7@LJ!AMcgriBxL;G*8b!ehz0DzgGbe zU3kcVE%w99sTO&$8LmoMN)P?@_03W`y6ws39oQdqoMeR$67JEKWztt^t@EBZJq;fG zkY&V2?BjpZD_nhchl%y5T&NQ}^62Gp#=Rn+yt@)S>+Wf^PI9_CC`f(#2F`FNhHiZA z?cGP#| zE^&kRBez>Otn5`PBYH)tkYIYjh=`rBN$)L77rvAesptPzct-1Rv=(~@%td>IKR-W)jHDipl;f><=SV8*R;LuFogSLX zBTrFkS##RSv>Cw+A@%LaG)$Q57{8 zA_^mSW1~qI?VOzl32F>yF{7WyaP=?)+;91}BE9OQ#Dq*huRB|hR94q%*sW68g(S`( zldyvS!T)69M%W;EoY;PZjfBjCFy!_M2LR9_RSasRrf40NGYi>Qv0>*pX%~CmA|Cyv zs`&Wwm#6Q)ecG?gUAL;mLnMczJqYq3$@2h-z6en|KhMwY&%N(0SrlVq!N?IgqDIPK zV+_eu>Vskt{Sl+V4lK;VXe`Xes2ZTTb&L%#h*B9n5a}MGRH{gZAR_3K7BOH{iZBN_ zB4Sjiz$6T+Ca-g&2ED;kxjud3H-c(0z<%`#YEZQn7PPb1!Ad^vE4yMvR_xee;4F4I z^#3;Z|DT{@L(ER0G$q*yAn0lBm#p=McQ6~V?)Urx2pC#ZFCCB)XiNa$2`DL{n(k&N zJvcIA^}ny2ednBe?|Uy(0yE8qv_brFmT?c0T^V6ys!WJl$bzPl^s34|EPtp6yj!#U z5MS!MMZAy9Gbc+kH?}Op5mKyT=xAfn(^er?6)jc2mo{_PdR!Un{_KaFe|dZp`-v}M zDdle5r43gpfvUoKU^U z2sezdyReGQLy9!43M+Ri$#!Xblvkl73T62BeI8*ajKWy>r+&b1yXWp_XjDQYB_d-8 z!4R4T$D$Vhi+~^)fVmYG4hsPhHljAhHdsXi8yjqF3>eWPO9Z79m`E6y3C5LiVdaH= zcY5b}QGfU6z&eX*Aw6?G!GoCv1OPA*rh%gFxPt(0Ll$x-g(G56AN#@X-oHJ}8=e>< zk)gwMS|Vi8q!RI@i4gHbB8eu3A9eQXJxNcNWk-(fbK>LV5Yr?0aFqK%sM1!R$}7+W zfNQrdTeo&Xw&zt#=iwuSOn@LkFlW30bH5=pc>sBE&d`fhF(C!ad=sU;mTLEU>e*>0y|G>$YoCH; ztP~>`L^%9U^>dMnT=ZMghyC+~5W-`OW5|AF4YKskc214rD+A{o==6>it$12R3|;P@ z8XM1>#G= z^{;=KZQBYltl8|VqErP)s(L2hz^6Z%*tbkoj}}(agiB7n$^WCyH@ju23?L`~Y`m<5 zcbEKx{maJKpV;sutp_8}dLaNI8>yL*Q&m$ny4l8Gu~W)rbf z0Ulp9{UQMtQFmv_?sRX%nAWfd!!qUtV$%?fA9!89F}55H1(#v0isgdc1yj;yq> zMS-vSOQ%2>$#M?-mg$}{mC64=dpl2fxim{d`}TTY&Ux25%eH(cDYIVzNdYLV(M)LG zUmB}dC`tu1s8m27W}-4@RtM;P14Zc7Catt{As+6a`h9D^Ol;oxV=mwULH4gJ*gD@j z1>`CZ8^j}|WR{$q#sC#GoXZV8O+`7&`(jg{A%jhlmJS0EqUxA*(J_f1UHr@G{-Hvf zr5b9DW&4=_GoU2h0yuzA-7`;uY0YIq)vVwqM}8i=d;?)%mPhI~Sh0p=a69>E`uD#% z`!Dv6ggqotKm^?w%a^M9r|Ewi8~_v?-8OQ(V=AFmilCqX43J=4QQhdn4p)euD%@>E z=3UyX4mCU0(ArN)bfpG$OW}wfatvKMVy}-bbvosf6lfZ9Z&I}?L|f+yZI%o~RIHpn z6~Hx5`RJ%qNQxPM~a7@_a@k6viS9{{O3%w*T@A(r^@^$gLz6*w880 z%9SejZhHKOC717i;G6-tdv-pt3A0KVZUU(UD&*MusA!!y+(atEA%t@5&Q;-}cV!pl zs@tM;SEed-CM0g!?QtN14}`j?!sg#htR-RAn{B~%fPe--H5#C%y8)0eZ*|Lk`1lfFAPOt zc{{VoU9QoKt4boQ00$5Mf2I0wvSR=PmT}9ny)zUXz{HlVwydhLek@o)1EMWxvEbJK z)upp@-~f)@Hu;x5POsRZjtdSz>?`*_&`?|+yXOQn385*0JfJF`iN(>FD{rY81chxp^X^28yQeea@ zZjP8Vib7asm`}<&uj5eQ(*C)BOV|9Kxgn*fSRo8jEvUueBwk|wPD^@zN@q?Tc!0o+ zmWllfc%F5j7`|>W;TQ%_|4V4ZYvwvG%UG0oLZ?sk%hiJMG6wSb2eSW&6N)1@)l5ANz*7Ml+=lgm5*pJZufEs;r^hqv=MRZd$%#2V_X3upA~C`ktx4h7!Yb8l+ryy#6^B9yA%qaZ7-J45m~>|S zeUE~y z)sQYbAiErZ9C90S*L}!CPaw~H0UAG%G!)OML(%3Dl=Rp^$xaoN^=XE(BePJhX46gX zmJv|7IP!<6nuza9)r~Q>UAnveTwn2UUyckkUZcAtY7mn>-Gi*uQIu|tY|Q6Pj&ZTY zaV&w!)Th(FwEp`NLW;cVN-|akK{mPG3m+Iz{3;VwA*xEK(a@l$&9+8`acTFPnXc5P zsBKX@0-?M1d%AGmO8@~3VaLgOw*cVIf?BS$SZWgq!*Fp!I=8rgZM~25Uj~ocb zoUs@#k4SPealPvsE=tgDiQ zYy@Gv=#6wL(JzTeQAv79Qdr1)$uVOS{A0H{dKAv^Iyl>7_H(_ zh}e2m=Ir*;h}rY#EI4=!5^9f0%F#1p$;o4parW5cTqbiUxN>{v;^CEu<%iz5MSv(- zs&p8#WXshPfx@t(`U|xGj9Px zycMVL|GlLG1(N;G$-oF?@$0K7sGb@Pk5YhedI>UMbfiMVwtw%fV_!Vx^?yD){qyg~ zKl1==`xAD~Wt#Vy`TqBT1o8npBEy~!zIu^Qe=C3*fc)B>&(rIF2LS!XuL2~n5s*-_ zgZ3H7!_7=LM#8`GJwSp#{H%M)bIHHTIW+&aEn8rqjaZxet(R$;dx z561b}mh|=>9^HIO;W)kka76qZFaZd4YdoaVUPehaDx8mC5Ni7!+_LorFN1}V@Sw{r z&QHyt(f?U4`r^nIz>3s2ZAjv^y|62q2r#46r>4xT^Bs$AA#C<6B!AgcA_7t=#@jWu z`U}&)4o<)b?m@x+(H4w}*t%`gv}Or@@Q6nx<2N_7mOlnqq!2U#NtA^sfbRO1iO{9t z982IQPvicri=u%V28#yi0Cf(&vgCF;(ri&i!#7Mgx z&UmX(P;-29wZ9`CkUiNzs3QT8fx#B>p`1DSa<9zd*#U=F0uJl`9mB-2O=mHb!Ca1G z^fb+*?)tOChu5-0V+&4VfSR8tbV}uYFl)iB;{oxxjU6St8d#67{9G;$$V>C7G$r}w zEEqSat&Veh9`0Qx+%6>M6N^N&9|Q;$fuDrIDd@afk8U|Gfn#$&#DsiC>02OT9GLU! z@I?ENMdpobgo&qZG4gH%tO%^GhJ{JXEgnHEPdOI z%d+%ET?6tf7vZgEzfCX)ynJl<)-w{Xc2<~e zf*6ipU6#M$V_@!i!z-4t*eowLOKa7FWnQBZ%T~v@zc}45ECFy#9I|gO>%6JaBgyIl zfBHl}R4>Uih7Jz3V*;sBG*Y7R-N=8hMK?q zCS*cs?F?Rwk@>%q%!x2?`1cBvNg%D+Mo?u*nNQG=CldcC2${VPvzd=(I9~480Q;o( zVWCo(=%W)hURx%CdJW*p8NgS&TRi;7qX(^;B<6I8NE4NUiW?fo7k=e{IQ_Zf_h6_> znSmWxmdAOpR^|KyluM6N8je6Qz^OHk^LT3H2+kX5>&5;@%BZ51({J9!I2)j;sc6a| z7SbV%9T~+a+2%57Tl(j))5>!^1c!&`bIz&U-m^kY&3R(S-IFz8z=(jW(&}H^e?^*l zIT5ZDivwO0tvjcWKc5&ZiJUjjCzC&AZ=c-?lO5-Mb-X0Nb1Jr_1WEwMmlM}=^i4&a zUp>d8>znH+ky#c32 zD0tZjv6vbF{D@JwvJW|5jq2uw?75T3{1re)AWLWL;h0EW!)r0{vF z-De2?l}@zv9n`%L2b<+KA>lF$ot=?h#?W#8I=(U_H~9kljFa+gQ=x^&seu7xp$e?{lMPeSJE(Mn zW50}c?@gG)el-)IISUQ5`BJL+5_IfZRy7Qf#;0v!5|0*&q4&hbXeOs}#-;+#gXtOH z%*uF>MQt05Vq%N0?bsR0UL{}*yIa82haC|DVdPcq^?+)mTQvhi@m~!~nf(HFmUIM_)RC7VNl%-+01X=WTrU6*cGV3I2Ed2~UfL&17modW$5?F;GNMzBB=Y++NK(8#7?7pmoxBx>Q9vI(9ZuXW7BnxdTJ6TvY* zNOTN#2{4~e3JQn_z|i}XL#X@2!oV6s=rS}D(T&=S&6A|jAR$XIZ3Wkhom)vh9}JBN zJRo?BJF$nkur^G_i5Lu4FxL7z$}2?P*W*R3#~3-m35U4=5JfyEQX_SpG~L{$>P|eo zeW2QDx17@O4%d^0howHpYnD&9By|IQ+EHqOQ4%l$7@;5p?}-lFg;+M5#`N?0ucpD< z%D&xQA4ded^N)Y=f9T#-8dbY)_y%t`d?U|bem%a$`S!luLc?!Sw|1}uZ@@O+Ve1@s z!;9T0y3#pUwdQ4hu3!E?M!ul;%loRnmaq3Ce3ZZ8AN*4rclL|1H*Usad@`&~cPr1n zGTkh5Ewa=Kt8K8&UI!d@%t^OBvG5__p~$!kYOq2a&LR05M*bZRupF-NpGy|2ZsoP&8EgG>>%&!-P%1)$?6A zOOL}<*!WqHSSt>x_GljHMhwZDEAnECxJuqFd_RKiGTfJ@aP^lF?im4eU~hX)*RxZ2 zW#vC^21CC!>D-hf6ggE(XW^&)(4_9t4ceh0>HA8zZ9!yW%4CIY%Mj6jo$^ng^U~Mr zP51_#g3&cghXYR_<`r*MXEguO-7s!+xBU*pK^$_}5l0D>4SPiK*a29Vou3ERsnyE(_*S^}crIDV)* zQc{-6J)uvZ{(Jq9dpoyn)_Ce#B$ljLd*Go*Hf<&RB#!)$qjX&0nk|;uo|f5cLw5Y{ zkG}~1AtKqeXWzkNs&3^Rv=E>}kHHmJU2`2HCd^o{Qld(YIt`k%XeW4Q$311E@r@EC zNR{oMopTvXw{}&hfZC(VfErrxPaVKXm`8ZbDF)K z7MW)fva>_VN$;~pe7CJos}~;H8rJz?Q@=3I_BEGH>@|z>C3KHE4qx*tA{FWAKqtB}j1e)l3JzLez~B5K011BLqmEaA z((vRRAJ{tkXHBOtjPl;#di7`fOMXK88AU1~xtSbbkyS)fot{^Ioaacpm42vwY)8bgynn+c)e+pF0-rRDQl`ii> zQBPr!S4<5TRWNP7SllaVofve3z#9VN`56XzqZ6e>gf|+>U5P`d<=|aAqiMP@mLTU-&en9;CDC*?S>|iQ878* z?a=&80l5i6oPx${4mL=$j!J;Q?U^moNcg**(2C|KZsw5-vMlatc&s*gT**0Vgl0wH zflVW2pn+>zxH&*q?RE*UuhT*a-%T~PG_c7X3@m}sG_h(2)@Og*q29d_A{X+0mzvb> zWjL;E;lWg&SvPOk*|ZGw>wl+d?!Y388P5!_<(^=veJ(%v)`yKU!7@YofMDqBnq>Y?@65 zvtba9AIayi$Fp-4W?rNL?Y5Ol{A6dE$T0Th6{pBIwO>R6YRmHZ<5epl%BVgWE0L|<3Wm(Z+g~iWYRqRyMxbq;VHhv*_IGr~BKTB#^=r{3}?pS%B59lQl^g zuCQgf0$myn*ht`;gYMBD`L_E~7rR`B|69C$$g^zyav-Ov@_|m2i6ybmy>m0V`)B_5 z(7sxa(>k|Pi)?cKmk#rfyXsE|wTIY6sIfMStaS;zD<5(Z_FTEDgK6377JUK1Q;0~! z78sAG0HAqbTsvVl9U>0T#Hj?(g; zP-W?0Q&z{XG?8@to}KG;wUD2)*MzXZSM2I4-_4Td8CTj|yjy&KS;oN8$ z^-F_Ek^g2c%E>4ov{9|UXkY^nI>U>+J?&N3KB3rtKZeCUf!rs}QK;jEPxO>Qeo7V= zZYxSH@q-v3dJpqf-HCS$xS*mUPnZ=y&squLu zyE^O-a2>X6dk>XqlMQ}s>Jrpc%+BEh=CLt%YzvmkJ0}eCUI;EH&YJ zxULYX;1>w;f4@ zK$J^$3x+h@T6yST*PwWu;Yh=*896;xNJu}IqT;xBjtgwo!upDecp-x+Mi~;5Q2`@v z2K(x=!Qo}|29t%8`9Lb_uQQ%Or@_6=*mPNBS|ibGR!ZgaGdI#yTKGgfp0D#E7) zW==GhsQlBA{^}9C$HIdz82z^@i^l5KEZh5n7cp!j{dh@8%j(%Eu1kfsUb(&1ZK(Au6 zuRXNcP}TeljXGC*_0lv$R&LHeqysvDyE+x>`tFFRFhM~}p>4ojGeRT-cM{ihZ}nAy zVu3nZP7y&mX`v?PNsO>-56gmP5e!a<3h8wPTg>%9H%}^Pp zy2Bfn0QSbUg54Q(+KDDa^jepRrYq#^xfT)wVM|R5Bi((>#!{sZZ;eMG5LVTSy)JgD6!>okNt=?SA z!xI6Vug?8zIcGJutH+5sfVi zhmk%KDPmTM&W`dwJicxwA+13uR4d1X7FcE}03zo90DE<^H4YdQs;4AvpVQ0KncPoWuv=RFD2eI zM*e_UYkGC|JbS@cnVTlcRHY&j>)wc>gSaZ#y2YE;9QuLJx~YBLx^5ykX*l80VWqw* z>Rh0eOeYQ;3n4wxd!W^UC@ba?BZ^NN|IP@pjO3ZRY1Rx0qi&o<0JK6dYIR0zwa~l? z-Z=w*)FA6tWmF&U!Gw)$I0K9^z;PV{jEZjxx^e{`i^4FWxk5?}?lKqbAjo9orY4w! zEI?E7pLpS8P@ez8NSv*A&Wtp)=H<>kE(MW07&UOoEm0aNLfDM4;?C6!)2{Ok0Ij#Z zt}4WSz1_oz;OnPvqkG;2yTrO)-T4*ZDQftks~c>pFiYe?{YAz~icqxaQ;b~I-V zb^(rwJ+oeDO85MI&a>YxyJix6`}yIoJKk&4akj2i)0N;bUWf*CnGRx~ zdCl6tt&7IRGO>XzAZMc@onH^YeV*803`rn~c6KN&pTrHIpB7_KjAwX!41|N)8in4J-jYYCM1FCV3mV9@PvN=A zF%*3EfqC1>1zeruFmvvy&FqW1lsaxVwL%u>cN_Qjkiozu+q!C^U9%TCBiez49@&x@ zjEuH`Kd9eT#5>P@fe@ldfPsdYk?#{Ck96oFmNUpO$vkLvUQ;MdwuS87I3f#p=asRA zsiu%z^_e6^!~o{U^{b;Y4@d4QdXKlHrU#*)*lFg@S4C2^lzL)us`vhQueWn#lvBZ#{>76>oj*{X@z_AVBKIGVu}k`pTQbk~;;QbOdu#yGIRrjwHHOl}w`ncCb=BPNp^DW=gBdyxCrS zk-h>2M+~IR_q%0v=R<1j!~?YbLxtG@GN~xA^PFfb;E=uGdWhyVnJEBX$XJ-#0i<+A z3IUEd+Wpb^Rs*S|8CJ7(!q}%Ot5xb?7loK>=4TVIn&|Vsa{>bwO1n~>xV~NqZiEf{ zLB*W~L7$8~0FYrgXu>uu85NO&PGxKhDTcf$@@VU4zqAUo7gG84{pkIrUw&m_{7)evnR|< zZ*>*?>X|FAbAu+^rLJM1+jl83F;Ew3z>b;_^Q6pz8*H*mvOWEfALG8Spqq%knO2nV zQf-$orp=sY8(SoU4Mh>rv+7Jh;XZYS;1~Ku52N6QK~%{oRg7RT#bvzT!X%s4UO;?4%gQty5ZeOg5xtL zmmz+1AZS2vNT*M!UfSi)XZ_J2Q2`=-oZ^y?d0{gLv%EJ-?7d-7R=N6Hs&MqMCl;drC8jv z&%ON2QwDj(W)U3LdB-t`1c^2dV8V;CjKUwGU?>hgl$v@8 zt|?j($`7@|B2!lH5luT11w~yD0%;4r9o3!e1Yh@>?nUgiJ*;8z0l%W^k~R zQluVoV0}W87CmfvMa2aI+~lzfD4{!@Z_;sP~0J3^x3eQwQ!SQmHVmTx9g4)1V8>4 zY)q*ZCe?4~8+m|vxYW58?2nOxR9!CD=Q9Esu-Q@;22a#bFOG^bpsaLmW0K7?tFERh z11a*-sU)xo3+@UJqel$yK#kH1+$IbjynqGEKkrC`Of+x(#~!;thn2VL;JSW&cgbqp z*ZweLzSI@;PT7g-V3uesNI+Ve1CKqXc(%Ir;a2mh2VRShS-|l3i~WwSlHLeQJx8~H z9c1|%XZ?Di5-Yls#ao=RnBz24dt$a|=mgTA4U-2?`wnsDjIYY=lW+Z9`WxYo5cmc! z5S(t(aL+ZL`TW0m=oU{erV-sZtb3YQ>2-!(Xo_T$2c4X-+S@Fl(abusbw0kn`500$ z58n3{zwAnU6<)n7kJGzLx$?68VaE902v>evccLrz%#v3vfeH@ns>j<)p87r8$*Y=? zPJnql*JHl2C9j4iMD=4)t|qKl#8#V8w1=hCgewA@?QN(75sny8 zx?9Az8tP0#ecMt~>;TCupJUZ%L_4kT#WYs+dgIt&#`W{;WndjFyG6=eZ(@Cp?HdAC z69Y^i0XiWC?Iyza0N7qY>IL{{f$s$MWa&2W0L)Sjf_eibgek=UwHhu*H3~s@u@i%P#{nYRH!# z)zCbJXUg_Bb#dpeK1z%o8xm0x0q;GYUMq3a6q_JMkj;zJbrm4>=P-Tlg^XUvrefKt zWE12oR+iQ()#%ZJ};K zzNF>kAjGV~ZX2vu^X&#b!W@6aCoC?%e$uQtKdVJ7)J3~ktPhhp`7i9+-5XmIyPwrP zm@~Ohxvu+Z>yYj`e4Z#dmKr0CdfrGUfl6pZCX*G4 zLB%p7q;*=o0e#-H&a_$mBCc2NvUJai@PzChj(4k-C{n{n)vmCPuAy^wwLQxTuA(Qd z(tagN&;aS6^QSKBa z=uq3}@VsBqKFCj+0dHjiRuL{QM!U50b2P)+7~piD9)Il|F{ zVu|(GR@6D1HN(6@7F=M-N_%!sx|elf>_Z3ploN$2%M*>48YdiJ;lLMl;RdKpih=p627ZB{Ey|_;_{)>wIra;qkG)X2G`rlp`@lY)TKHaurVN z%s!H}-s+8VB$JHEUoP~`cn^|-&mHw+>xp^s$FEXdr-)pGi%q6KGuY;w>zqR7cQf0a z6&*67_BLu^ez!7g&;A;3qkdhVLeXO$8%Y^cQBN^851xl1i2Q}&)@|}QzMz$uJ($E+ zQa%3`*^|mp=|e?$FO=M9IW?C^2pr5Ur0`*cOpW0QwT5k1$K^Vkm0W6{h26y_D3?CE zVX&jXyiQX6^-p<~_c7giulW1j_=)t#k~e;?-4+is#`i|J@jbc|-S{E1#Em}$e~!Q9 zf7ave=XmO$XFGA@KSw(MZ+>E~$9!c=+}(t;{#Agy`+h4H@r_>v%H8Fd5|k$!lNHow zN{f2LkGA&a(gz7t)H8?V`i?W18JKNvH^w@cpN`M*D~6^KPV5~$_dWO zjWi0*9q!+}HR^RJ&UzT#$B(?nKY?lV#@@yF7{A9n8n$WPhgE-;cX5x5V~&T#2OKE~ ztIO$ib@puHT0uPPig8iy^mDySvD>rY1y4y*B*nuU`Z`KX%-t3Z zr&YsI60(HkOQls+0FVYO(EM+)szcoX_1*r&U|(Ix6JaP0(A0j{RVcgcOPU|8icoD+ zbNq+}J1eTMLj^@nT7Q|irkP9gqJ}5E19S!b+_*h69;OExoWl%d7(1sftp4I!FPIQF zGMbLXqbSH{x{+Iv)YgY+OgfYGZTJkv^_oLlOceJH005KHF5Zobv(*u%2AEEyQ3yht z#_1V~@W6gesFk9ep!D0mvjV_!5&+~q7Fhq^Xj#`D05$^L{=}!gx|3(h&>O%OdtXCAQn|mr&J#fTS3DX+(t06`JF zsK88F^QgJGBN0_rKZc6HkmasB!9kqROZO_?WN}(G zWT{YRHEBsigGv9+{VtlU?@~oY7`0K2PMyVy&SO-qu8*Or4KUANv9U+v_abWFftP1= z51iJ{l~`$q;K6Ck8s98=g8HNgpyGY~ zsmfMbgq zf>T9ty_Ji>b0ql4bwNFMM>0cd46%oLMk{H3Go;0w$L+X>>4LXdhAD-MB9=-;>%;0x zcNsy*XRB+Rp0l)?EzX)zdLo?a8vl6dK@&m~HEBD3nSj%j;{x5`J=TG9x6C~is~)WG z@Dy;yG^f6(uV$F(bML~D7UYX6zwZCsW3_r>4u9%Arw2!@$4y>22jY|q)O zk;s?gIHy*PY?dOGsn~W`FM;Cer6UYjKF<&y8GLwq?mdcYFyDHmW zRQL5v4yZov@jgeS3(mtVEzztac%$4$&!%B71ppc;8Z=gG?T_|yq-N1s z6VagaUFlkvx~bR+(>JY}p*o8dod>9P*f(a<1~6+>0o^gp(2Kx{?C*io+BsfkECI%B z8w)D$vE^CqpA$F#WWS%`e(8bppg;_tYY6pJ&$J?$sFJ1{x`bevyIr3O_e@75z->>& zl@&*7pbh|84Dsni@M&<22Rb&uaVmNS>$h4tq>aX5Vpy$9Uta&bn)Db=uGL7j061rl z*zg|fzE+*O@&O#-6HfU}yXeCY-|sluiKEPT5qO$>Vkuo*>r1!&68Rs&Ki{{m346}c zYTr0(Mkx_abxn@f+-S|eC4DcwG6A?sSVQ`arnBS}F1r@KJqBGNyoU685^)wc;JKSM z62meU=hUi6&XOaew*mkpeb!mBbZ^geu?;4WRcytWFB$hVpe$sFtiL(xjh5R8?Ki4(k~{@2gu85DFc&>8AbP9hk8on~~}<>7KerNl3h8Dh}!E z9j1|-kP7iL@?(x(Tjq{tG84De%*`_2O)N|KK|8QDH(`y?S>dqk=U!l?^Ipr3o=Oaq zO>Nez`IXoEqeR`gLm3pZE$K32x|h3vqPe4QZp0kVX{N3ENLIxeDxEUXvV^UAtyLhq zVKsfH7D`Th(&RhtSf}@-W1jg5^Iml&?&F)YNp#`Jr1362lSuqH6s>3_E%BkTVmw54 zj|^7!=OA6$`C7ZzeHO0mTPd*>sp5%0j?baJl#|MrIdI-v4v>#jqX-{&%NpWisFK#F zMNT>pv_f)+X}LO$zNzS$=EdyUlBQ`cbK6&XhDKNsVbSl5gOA6Ia|Agu&S%`(%KUCd zYh%?L_Re?h0Niw%uQ+jk@#-Ms@YAhV@j$r)B-awUR(?N$Mu7xYBs&6>3g?5*`UdKO z;_>QQvBoe*Vh%>jg+M}Ri=>qnZ368?XiL$~C2fI>4}*ay(9HZV+ZXnV0*r1_Srien zT+RWachb@9YDrJd3;(*=Q=rf7FyiZvzDq=kfr{pz;~?Y22qouJb2{O$Y*?f$$|ahg zXhz!$v|U3b;>pc(z+U{J_*~^>_LQ=>+#xHduBZ%F^hD%)Wdk_3oR$1@eFNJZG2mos zF$o8%97P{ShY?V=t4HY;qAL=^c{R~nB6>;m{0L&M^Vxm$P76!;*R!u}`pM~es7m05 z3c52HI9+xC;+;*b`O`Qk6ae=V-SpmkmG8fXLc7AzutU~1<6Iu#p|I#-ZB#h4y{&6U zO@F{0ZZ25!j1cC0pyk{m)zOuBkOx@dO-HXSA@3R@j8VhM)1-kvqXXX znU?^cL$||C!uzVs)O9EYtB#q?qAIEiRZ(#M zq9Bxl<79#GD&JjDxF|Zb-+9ucwB~uYrZw%>AWw~_9m&L5OxdUVpazJA(WOk3nXFPO zxgP!Kp?Rj{wm&llkWJ8@Sxj4O9!f!XEtqRNs}{?mlEaelLpfv)|1u>Vi5+?bC5J)D zF{ng^>7G%3ptdTdf`Mi*4@&IN!7yH#B>>a~1OxyFzqH6sc1aYyp(0Kn%a8ypSHf)_ z6d}}5lLvvO76QEtOGNgLM2(^h+e(SkR@=74=VBYGt+uRG3oW!@(Q2#kEyBXW!r&lb z@Qk8F8O4gepOzoD0aQUj;9S5s;9#H%E?E5RDN_f`C(d-7)3Pv3uvoWk+qP}nwr%U% zwr$(CZQHhO)v6Z;uE#L=-U9xPE5-cMucnz}-_y$FJ94@(IDz)b0F; zF}i%=FFLat-uPYF-)7#f@1_1z-G5{CAMtoU{Tp5Rn$cZ+8MYlATE5F|+Er8MhAqo# zyH#Q@Eqbk&$q`gtUHL8-_bFicKAxPatdYlN>E79`L_GBzrYBS|#DemJ*|0KurUzj` z4lu^SZ4gC^U?i{WJ!McxiiPzNTGtEz!qz&ElPaATEA_t978@^SVq5z#Vm}su%5;nW zIP=-yiXEnU*XZ0ve-3VmNkB`v`FLxx#>dkFl?ADB>OF*+94&I_8Frld?l@Sr*D(aX zQtx>t07V8LF27BHuYVtP5d;@7W*7e(4BUn!=e<|R6UXyD%sA8YxJX&s^|;D;Lv^%i zFx$A^;N)%_?HJ=pc8_)Wa`#B~7o;kRW&6m0|22IPohr-p%Cw|sD%RH-@1)4(s|rG? zb6Tm={Q*mDNK~ypV7iQT#K%*TolFR6$Vrft`IO z8~(fXyFD$LPjtb~OkB!{InHT_xN#fd-sR4Ax9p1@F1h!5q8$2}B(URaGH#1Msopc{ z?mT)cuI(&SyRt=DnEqO_IgrbW;=T&=I2*Vu?T#|iLPBWoRs{^Q-oyZNh>B(i*xE!j zbAT7)aB3hvm^R%NYIkmlI+#%3iImZMaaVcl>{6VfFA*6N1u!{X6pZf(h_@zyUK3a! z-REM!tQ|AK;^ja?4v1bs*-x^i>T!$=>sd+S z0mqf@%|lg2X|$sq5r!OqiAk=8pxhxRHl^0IoKy!?>YysNa+P?&ieA3HB2(hVk@yLh z7;=kYvGW7B+$5ElDrfX7o@n4u+rsi1JC6$deUT76;&d_+Gn|J}W*O5uvq^#?zG&c` z-kC9jj+~qE!g$hnis|glyF=F!p@`7Yx=RN3XY)O-(dN{5?a|E%N#dwT;w*u7PN>y) z_v626dA8rAI<l&f-kaoDD6{P6jiQj`}H9Y3Uq&^Oc<`_r%xKSo6BD z5!k!5QjEHxF6Dh~s{^)kkqF(wy@=-C0nl@U)Vz1-1pzWhsX&B) zf>J(jNT60L6tv@uVw-j2wrSdSL{L=jA8QK>BSGfgl?lEAbeS3!n%oBgZ6+a+!fLfz zD4S-->jjI^VlmM<6w7g$zC_n`+S#>p1t{+^$(;Mrjox!?TIab1&iC3uzwaJL?4|26 zVY;^SG(YzD0x58v@JujFoI^Hc+q^`oP76_qK1golB>zmRKEDWzi`*Dlky1)CcmIH(VzRL#p%zL=z}tczTV^EIT59^c@u_AHdMeJIqsWF=yYbgsH+N zT$)|Th)uJz&az>SYKFcb66rEuv6DsWk!%*485Va_LhHiF+($?tbt2XWBFY zxFV}8gIylrDfypX@UIuV5jNnO4pC^cSB%bhlF=|u4XdfBXJf+nHeB`?%H2B^9G`rr zUpMUF;^Iurl;KFSP>DiE#I^`l!={w1OAMKE1OTwXIE`tl=8=V5QnTvD7^MXfE9ABv zYjUE$gQle=x0`CnX(DFvVL*Rl;~QmCjL>y`;CF4V(kV5oPV+msX-G>y2fMKQKh2Hy zMi%!2n4KBo%f;*;V6qh$xH0$%C?nY%rRw2rdSyAI=#^7fzp@rvH;2(4CqDhXO+#`- zym*RSrijaoH-S6gc)`WCttN|ak!zzt#96Bx(M)BN`f<~uL9R+HOY;DO^e-{SfFxA# zyZl&3@lsYuoy2sNT1jcttS3Rv8TP#H2#e<;D1eC%oj@kkeoYH@o_H% zQ}prVJgfMd{nw3FjHD|x$r9NhyehQx8&u7K zHRCAOt&?aI+pvVK%&W_x72y@y(BDaxmc(eegBMnC5G1oiP3kDIFN5PsE5gnEGn+)X z8LiRLes_iNY_oMsclPAcD%D|EpMOJD>ecTphQ&hex!`~gn!FxGmTG+^ zrB2)nJyGV^lx(`U9rcLs`2?oOr7}r>{lqt{#!+3}?)1-ydQZjlenq#;?S36bNsYX% zE{fR~sdHB1!0vh-)v(hl+C|u-b_MBG);@!&1+dHNE&}b5+RI>4nzA6MRb^#;m?pNcA1E8)yTS80=4mpTfY8d___HHhKXiq=?Rs^k_z zN1I^lX&M~9J=#jCNmOt`}&`48) z4VpGU1vRJ~Ho{H}hjR66uy*LgXi=|P_RmYut(uT*i_x)9T0|OG54K>XHIJTXN*jlA zUY~WWZbZ&;2deJp!$k9J>xX#hkhnz@g-qRQ*T;cS&ZlgtZ|vUx^B#(GBn1=@6{}7- zF;hAQK(UyQ$`FXr3~W}#9_q$2(sEg1&3;z*0&>m5$jZG9=4owc8vpOxKI#zBFB)bS zG75x5h>x8tfP(@}Gig`BW}Mw)nuv&~Nf<^H(Gn3fs#``oJbauc^O@JxRTWBw;V)-Y;bM17Pd zsy%cx1BZK()_Pu*6PycBdClu8j1+KFT5s~Mz}*&PhlGXBle;gB55|Bw9W7dYcFYn|HS2aI`1)8+JY3HrEd`Us0_N=iS0h9(Xv@LByWJ40t$0^Y;MVegYze{G6$K1x65y~)SbetDxK}6 zU$;)zJM?!-(FYGEA0B^P%|$uPUqANz1Gt-qP`R$8!Y@W#V&tA2LJmHz9;<_W(hX8U zQ#A~Nb!pxIAM&5H=MbrF2DuJqrR;>W;?daK*uAb*F8Y zPk;KO-BU=1&XBt%K|mNUIjQ+5`0uo2#M1M|Xk08%<1Um|jgaF-ps&z!N5WuH}LF;6RmScda=!{tD zGrJWljQd9|&??G}vN}0lItW`#`3nNkt(Ho|o}gPL%pk487w{iZU7FZK#H&PfzlBKL#J0P>Gg_hx^+szm>`+PUlW zwV>$lP)fvm=L)h{-X?d&+o6yYu17dICt*CigCToPzfaV$DgYj2GpozDdqtvB^ZBqm zAd?Cvf=K#!+#e8z=qItsdg-1QCSBFAMs^jqNME9Vbj(Tsa9f_b{)#N7effPmyV>eg ztp?do8vMq_(BJ*{ShK<`2MSNu+h)V9c&5Dk?PHO^8?)SeF9u5^VRz^a)!q9GFjPxh zLnAv5Y_R;Uk8p_QkN55=5ef$*49;8*fF9!6K_jo%#`ZzJQf^e$9ELQR>=WdSrWn_( zc5AMMDcM~~YKgC{I`9?nYe)MECoNLcU`l!)4pbPA6iGX*QT~0uz9RmKvcJZ?Pp6y; zT8hd>A&N|$=jmKZLAOHP$Tk*<$;7HDjVQ&?`Xo_q2)LH)DI+srB}U8&8F5=}^k`Ib zXusU{(a&khGwBuH$%^n|7PT)uoN4Y5j>v)}-0G!n1%+nF#IA`}6YI$x2<31X3bXkR zzK@Mt`?R5*Y3es{hJ6Vk8&s>d8u3!A)|UU<526&Mb`tM=e2(KuZ$z{dD~25@rZ4@P zO!bN_$uz3Pf7-FR*P-@Ci+%BCr0L4Nxh=)rI-(X6l4_8Y3b?3QD^q8nLct|msFf;O zq|g|lx^?SmZ@#P8F)MFXySpOd>BPZ^O3;WNFnUG|A;NXP$QOp&6wFQ+)1U_1{942v za;|Exd&SPc(PFEcU2`%nor+Uq$42DJ`|(LAzkcWrK2xn+izR8STPJtpnd7wYy}^CC z-O9MeT?>F}^QW@~Nbw*P0-8i*i71Nm^X#U?+a zzPul&$n#wC{oOq@iaTG*)qjL|yU~n={1~6|}&&jZ34vz~@Ee^6o$pJU))|AFt zH(?DW))dwVZUAIw(l50HQ4NA!jomS!0A&Xxt40KZKQJHykmZmR#IhltQ=NeKynH&XrrG_RUQ5=qkqT9=qc@$oYoiIIrzdqF13EhU*oukU-qi8<%&RzD9h* zv+7){_w9}4F2_xr9d;{G>R#fWvgR{gbzf<&_ww1W20nYTk-GMpTRz&SEqjfY^28rN z<|-u_L^R6al)4oKI*~B_ttFJkRI5@ST#6z&p1=?^zv7~#MPhTF0VQULql{NfvX1%{ zZ9a!)*3^OdZq_ugKLVDiU~k!K|9Up}eUMhnL6`^1og~UNCBl%#M3Xeqo;?GQeV}n# zkG!L4(WI$^{}F9Uswnd~6iw-xB3etFK|!WM5R7D13<|+tL*A<--93Pr&_x2%^5g5 z=Zm7*t+o|#hu0%uXCCSi?7wnjDsurE-P1qM{}aSlvgl6n3sy8xo=iQ*6F!ZSh$KkC zK(`C(0i;2KC<%ZS-%3ambf$&WiifVbQr*%>-rBSZ9lH8y_fKP!BvhVgrmdkUB7;3<~!{*b~O+(?%z|Pu1NhPHVr&1{GeaPmIyKDsNy(Nw) zVe?=qa3MxBT5YY9qT-2aijMfUKAO@0x$ps zfxuy>C4rap#3sWjRk=z9mB%RzMmv1VsWe^dW_0+d=9vUa^Bu%Auxu0T(r-orseU`E2!k2<6S|Km_i372{QZzFp>%)vshm&%jurw&!b@#;3Aq@YP2q!> ztGx-O4k3CG;XqO<2}4j2r3Cseo*IUFmg%{RA>C#4skZjDd+TlhJPYq!3R5%~7U+W1 zhf_GA#uI&tq(f;-)Q?pOk%I575ZmlQbZ^lpmsJ`)&t{;Z6h1kPPl_>zSG=K|BZo9s zJ35W*8GZ;&ewPpo@P=sbd1qayr$-%#=GQmBP~A=RKlLrlEZpY%Nszp{z8R)vZbDiuF}1`o6d53)g- z8Sb?F9~?Gaf%0cZ{h{*VxT1K3304pa7AK z2KhR5yGCWA9TMUV3eUA(9}+`twvSd{I}zFvn;Nc2LV*oJDq>d z0?^|=dw@x)K4O-9`I*8l4pGy}DWz!VA4?^a;&L&tp)$kBETv{|U+tzYI8nq)YJU8g z@>LF`%1z+JZqf+|2_dB%-n%^bEFY&>@ zUhZuzI3VsskkYe9i{h5LKI z-4u9pv!EYPryU+%wS#I7aDcD~6=cEVo@7W9L~TS>oeETsmhLUyh^H^@fL&AWxjtcK zzbBecTiz7H>a+Uy1*h&Y9~*X)zsDR^_cBO6**&3*m(tW@z_yZk)uPE}xdIZ*yMZUMbGUIE-1PUcst^3X1vhYq8q*1nuy zSlJz?neSfgOv^Xy>BbXm)mmsxr`>Bhb6vM~)U25X=n8=pJH>cgLxkP|;lOSO1lCS> z^R(~b_0fFmkbU$2$tceVgg8KNTKuIBC?tBYLa8J>HDiS#(@63$GZRRt0VQ1`;yz|M#A|=?0 zb%PB3px_H+oK!3rW^t;n9i~nH@eu&%3QtP3jJikX%?Hc2ywvkgDyMsNfLXFE=v3Xf zY@^2ci0n*t--~xvuo1tu-6PfZ@dUAEnB=m$aUN8T@ev{%iW4xs4trqcO?iLcRUzue z+*rj|UBtUIF}tmW#}nw6m_60BY)P*1JYX&m34#!NOMOS8?h=twF^EJ>pq)30$6e)q z2KGx}XdGucF{r(tlS>v9{IZV-U0u6Q!p`}KB9KHX9FHumdn0+K+V~r4wP>64{FCdt z=&%om%Mj;)!b~#`!OuYfhGka@8(}+l8>OZ95r3A*-cm%_GY;vqsECZ7H>)IN+q|pZ z()$d+h!+(pB#|4B1Ylf5sbZRBk+yZ}=XCFWMAj8d+>U7UAf^VoD4|xgZN5m|xX#ye z?|FsR6A6%-m8 zBrdp~8Ix1+8yO}fAuKC2H84BbKi%3NvlYfoNK{`~2JhA|)rJWZ6wv)VGuLNK3r`Nr zj71zCofx7g>5P~g)6Py+b~w}1m0k-vWoIZ8}SQCCu2T3%oWk?H2S`+Brie_Uba0B+WBj~5;0M6 zk*Ut^4lGP;gqpO!slVzX)rA+!mFdxZzu%%8dxa?TcH1R;;}Aiw^%?CSB_}H?E-=@c z@^qi;$%#@I(2!9Ytto7*41Il_?ScB~FKWo>C~1*>C1sGX(0C`!`HQocbUdOagCm6G zM5P60rXK5@8%qqAR}j&WQqz+Zl~oqsy9W?wcsSgdl;6Vf3KSmT5El^B-8|vEj))DB z7LgK^9fL4BIzI3#XNRTjz=%UmnumBG&9o4^)f^R)8MF*-AF>~;mzHBhPI4fdCLZS1 z*4Nh5ot1V?nKTFoaK;`+?v?EaToI8ObT*9b-v)UCO+PcR^X~xNW$bEkal?d4u2`_@ zt~k}Iol^70b=)Lvd-l8_&L%`KA`;9G5aoGPocl>1Bb$AY6A*f2bCi^|o2Qi4-6SA* z^Mxhw-~O8dKwY17wf>USBWKm#k&%Z)l2{e5=wabp@d%a2nLPfKfi=^%_`N$_oo3kq z+==BZSko+%?yD>VWk1L2ct{!0@3Lq2e>W&vyCLHu1c1->Z)u$ZH=pf!t%kPno`}}% z(lNO6FthN*B1p7<+_(dR@R+{2)d#r8Cwxd4&9f za2dM;PRmj7l8jWTWZv;2*KwG#)yjqcDVXIo|>YIkhU8C!D?C}pa z+?^a#tIBe^Bd}IAnR}Aud0o|+g#8PT`ljZ^X8-HSvGlAPc)@D*#bS6G8JS}RZRHW0 znaok$6*6>}wHYgDw}AgJnI~keHc&nPtOM5M-&RhfA|bJrANSAlD%NLICz}w-AWCv}`AGp-dl5xgToc(C>3LA%D+;OIyT9Ks z*ZzC|Ji_E-QUSn&*6#zB_`<0(tjVGln~&kV*1+HAZD`Wb%t~te8`96Gefak!{>Ms{ z$*#&uX;Z2hqdaSwzWH{_O7;1H7S04og$}gk=M7_)S_4HFvs_GZ^qR*&!jGHQmqhri zA91r{#904RwM*02o|p6P>C*_m{Tr&^T5B&t3{6w67-J`647#QNclB8IIspGtC0%o2 z_v+o<{%DNT_sERHeQ`iw(+7V1p+tFaSY@%KrxCwH9o5cWT=fH|-~QuU>;HRf5AlI+ zB(X80_v#!!6z`mTlzq%%&N(MaC+rFEhBfNo>il;9{P=pZ6{qj_%T6-}UDoFzsip#Z z9%{LPz`6eNO%Q!ZGIi5~Qq$XM+2xB-c4OzqF}lrZb#;DufsKKMnU$WQt)Zp4wZ0jU zfItBg3!zHM0v1(t2q}V;k@)Mt!WA@Oi_Ha{r#d+X4mrxi^XQOU2NHO zN~_gswNq-_mA@Z9Uw(v zS&MhaemefBzNz7^PLcbLBteldELFX5`3zPxG40e%FbJ^+iJ}VJX{f~}0_Vod4^hM+ z+0;!zt;BA-#-5$~;?~BGgFU0xwRH0WK7_bl@9jnVG~(2eY>ceTVbLb)YigUcKKqxK9aNOm6jhbg6;_tk z7FUxn)Y94za_!+0pkPAp7C#xeiS7>JPD4pcT~}UR8S7FRG1_j?#jI28wRk#n^#|W# zQWZN}i^uEza(lbfrtg<}1ge;b`v1up{-}B923{Nhku3TDnbwNz*2@sb%v9&i*qrEA zj-cLhlAaXAd7+^s>LLO{Fd9(k_k5tB0Pz~Z8ez1>02l(A5Cmzo>&51)hG`4ys+M_A z4BNU%lM_dy1`D?mlr?-f$oZf8m46T%=XH2dEaxxaB~QDpy(8cI%pWz?c|K25I3rbG ziHkA><(Nr9o87l;2$$7ZV`Jp8gwQObssvhPqsI5#MTL7E2dT(}R6U)7CJr^Dri|yH zSMY{H)V?gJ6uVS%+#}T!=_#MV{gV-;SSMPz&82__v2gOIUrzMW|$z?)?d{| zvsZ#*&(+=^*24HGYe&Wmbth?!mGD;NjlmfAN(Y@w%{x-(UXl`+3#_Vovg{0t?AY_{y-$YylX0qH*YNyMP5b0!mZG;Vt&OJj=K3ocTTh4Ri!!y=TB=)1Us2Av40@-U z59H3BBxN9>x~JT#@mXRqfP`~P`)^zK7*rg5@7`~M{5nH;+!&^Im%QvgFSztM@)_o<|6 z8pcVuaGYhb!{LzBOm?0KI(>iR%I-wrG?f;GQKYpZiBg0u&rB0UT{@4H<>8A|m8G?6 zks{A5!YPGZ+#kFj+21)n^2a3dwY3eT5CKK?AWUHnGzpW(k0V`DExWg{cw5Z_1l)BOLlfPuNd$pG3w8ukeiu@M)8B`TK)(5erWoUBePJz>;7#RP#NkKDtv_@brj$1=_ejem$u3WAm* z-Bm)Y+~>%ov8pJDSDCZaV{yuMn+Zmht1gmRtGkqQvFd(`zCqA6l&%?Hw7hVB>H_Bq z?kN~>upnW^#E|lp^_ujal0hYr>YQxtJ`YScY#=+A_2zvz-kyc%r=8Z(=xBF0xL9{c zjBKCxv{^$Vf}p_Q044rUWfu9b%gD0J_<{=o{sR#LMg>9zM1@~_??~v_Obv;SA3mraNSh2s`ege2Mwp==*6pYCLmPI2b=8 z*{=?b(yG0@-B~Vsvg!OWC?6CoF;+ieX{g=Lu5j$AbX^JE>g<}s>-G4&G#%V3hR>$W zGah-dm}xy&cOtar#?Gb1M_PyUBT>3YtL2rkxuB41&u5@4zp zE`4dV@%imJad@n*$2=~w<%w&>J@hb&v8I^I(bwe5@HpzqMb8tvl_OsW{tw0#bu~}2 zF(URnLE8B!&Qu}T>y&Y4ya%GH!KPbpc%)3n!ci^p7L}lo+A1EZ9QmfW# z%H8r`Gd#r{uwv!)_{Z*gx7{q-c@foVF?!8|#b*V-cJMib%Xf6~@spF_9wv1U;Nvq^ z9W3+(PwV}cXiLZu=M)b1X0Y@Q{x#sa&6N-SHsF1a3lw%w=oOB87zP4^UmM24k?T`V z@W}>n7f>mTbEiN<%$;nnn~Xmol{|KJ1Y31ZR{v`zVX`^!%11s+lEatRt5Rtls{q5Wt6TVpp+lmU=ZZfm~O0~&8}s3<*^1dx=C#L;O1?NKZu(W4}T1^|=~Bxwhy))os9 zY`OHBNuyfBn`2W6h2sB&etj}CRNZoz`N%#J8xM_5H5wLytBX&X?Uv4`(kgwLOD=J? zgVBk;{(R0cs0;USvC={Z_%|yh4>xE3Gf(i&6)^7uS2Dlw{S$8p z5SYu1L;&^GT7knEwDgW5?O*eo9^cizm>VF`9pWD-=xrzS++0^6X7um9Q zSLgUTwMMYs#}4t9cL|u|se8&$fhdn_NoZT5WmVkvoZ=e=IQHcl@@MpXz>`c}&tS0Z zPkPNxd`6fVC`hD_IT@1K1xH@Vtd)4#@6aoJOMPApRCA#ot}2d|n=&i2RTyp}2mE&$ z{h8KLsK?^dGWWH(^XJukv4s68#<$O3!a)Gg?`er)!I{Pa-gaPAR;-CKg#L<*ZfqzJav3|ZO06^F;O7zH z40zE0J)BKrh&&ndL2||59ma~&>FlNLnQnh$;vWznnfnF_a|gYJv6FrZrP~gOfVdno zGbDBCAw;zYEbwN|Z~_Uge2A3tPGt*COiOBvt6Nm-njj^fNK(jircL@=+yLXsMSNDq zbmjP)4Muhij#o-iwlp2clA%|fQSXLnUEqjnWo{5_c?EQfrN8xVcT+O2-d>aQB6W}r z61@aB_06Jb>hu!63v<#`m?x_8aDvE091^j#X-KsQs`w{dGbSGeJtW_;ZQ?(iO4SD9 z-dg#FQu(81V;?b5iCpy{?tg;d`QG?U<@|#+NnaRoss+Z{Z*-1S^i%Z5uAD{YdnrhJ zlwaDHy}oZV)pTzUsJp^B>l{U=^m{NS?{mFZg=Exwr=m}pl(R7Tj^?lL%B%+c{p5m>uoq8 zshJ8$kU7~TiFdJ*#k)713Etu%-Hh0CM8|v5^Dr=I@+C;a+{fI9P$_DwYy+vAg6-q( z&1D*`IezHtpziB*&Cqvk?g>A$be}GF+1J-biURxUB``ayke zc%Rn3JL(Y%noz&+ORqE#0XMEg#esbMAz$%j(m~wdng0Y1d?C*7u_mJE1#eLS;CS|- z-~+I@_E0P*WE`;;b1SA#>?Ka<{7NbnQZ`we)?ZxcK++Ik-XPRlYvt`!$i1n+ zxqr@Hs1x(|5v+3h0H4AqE;vbH_plTRQ5XTCmlH6*Xxy@rqay=CklB4}gp!!0xoK;v zcf)Q`4%LsTkS0~FSLD=rX*G?~B2y^TE98>YbiFQbWGDndcrk`xe5a~$k_M4%fVJbp zSxgEsc&F$RAO1d1+xpIc#Y$85EJ|)|&L2@Ri_%A+`(W^my4CYGY(mnT*akvMh0R+Q zM}M&le9Zf6NThQSxC{;p;M|&za>nNtv-h%3+p2rC-K=>UKq&eHc$kdB8n8*i6LT|& z)o){ji54R(rD%~w&&_E;rHXTE=y*`08+TT)TF(7(KQH{w@j@}w$PMRy9%SvgUw=Yn zqUu=vqD4cO(u`?35E$&dZ+g7MV@i!zUgKk|jdyAjVG{jN$$kTNsWi-{f$nGf^@04L zzkyHvUWxw&_NU72!W@^F|2`tVpU8(jbZ(VxY}vTq>V?|r>jAeO2KQltalvnd!Bc?nDX{NlpzqL0Y09y z0MK21oaE7;=oedDFwLykJP0e?uyw4^(Sn0;i{cVqPWAr03afLcC#JR(w(xG_-h5$w zGDy>4*RP)T7W>*V%N0kEWl>F1S>w2DQ~GrPBzd%nXvovMe+VNN@n#s#sLtW#>ze2C z>$qdBT7Mm5{RHCUS)IpN(BrPZgX>y#hF-9>TqL}@rD~S#Twv1K7ha&kL3J@)dtD6e z5-szkT;wcl7&K7>ILl`Hyz6cc3Gd#gw*9-7?!APsnq>Exl6TE9+~{gP!=D1iURI2| z>Fj{*;nCN+kh>*9K;R9xeO^tQ7>ZR2URM78>z-txwf37a#lIVxZncG_)|rxPd$W8= z>rJ=Mn|AN>b$|N;BVSlXJ=WX1rQz2)pwz$NFiz!$)<7sSP)0~lY(yT7qOSpLJRU!? zX~rDIvJZ*vnPNiEc2cW5TU~A5%*f@l9~m^IUiKB>0xe7%)g z>xi?~9}89KFf67NoMB0&G)>Zivn-ZF-dc8)q+V-|mtV|5n);$y}>V~T$T7g?F98Pct!Aji326?PI>EUTFrn8q@YOEmf5<<)rQ~%q8Xnr6PFG>_;7?zu+s&D) z(^F8&07-?pL>w%^&sNS0424W1LbNCCGDRgrxy}=R-UqvOg^_;Sw`5GDm5e6`6<5M?=q{ zFMN#B{{S&jFbD@SP4feTg_bjbEKS*)fy$o4CV5RAJ7p-9NAy^_g-qYrK2aI@-lZ!W zo?RUq>FU&GRlPXWO$+gB$>VDRvA$Q8HD)TDh9JuA_0y`y7llww*%1Z)b~7$Oyr%DSh6aQgLblQsk$6dBmZL>`CN$vfJGw%+z6)ZX{NrUq&0TxA+8S#h6^xFChOhH35#^I-qx=L-2EQKr zuO2oWN#*5)M|+DJ7dY9Qdi#NojO7pa+p`u@5ElBmoU?2mFJ*E&)Y zzR8DFOmW9;!8v+z8I;qcRz%yWh94@d^LV>UUj_chdH{MQ2DCkhV>Oc4$c6(?M_`m- zM{ve|`{r;xyon~u3)?qx=*kpeQKy&e%rO$OqIUgSpWc+@InoY}SUn$7Rsa};zI;ZI zQ^J)%glSCf$*?k>l$}NUVmb@h&v*7dR;RoKWFK0=4KQ^0_r%qsLu#JjI#@SHmb^%Q z(I<*tcfFIB%ozig`1L}+OFM}T2x2{?un?ny9%ARXNv=3i310d znN@ymSTF?Ct_A)e8vuY*UM&!aW$2QLo)h62a4Na5$Pbe*GFnIvT542s%@BccB^aJM zusQ+1K}==7;>rdQ$%!kljP^9&4Rx^oS2N@q?MJ1sOOx_LP){1mBVnbLpP6;y9Z~LW za#SrV9yurmHBOY6AKLwe1`n*P>Twq0!+9>fZ(CCiMIAX4*Z38|LVQ~kP1OGCqRR$& z_*P$y5r-r@<5(M&<^5Z7+FQ|)+)@r`CWhfF^h&p*STk z6H{b_QFe%{K*bd&<7rm#L@If!m>w^9rPYf`2o2mJDZ}>MFjMnZh39B)mEG;m-nQ0> zmk(fK(bHC&ZP{})s>s@|h~Wx{xxQgELYgR#dySjL!^Y1LYWHvREt8}#QGt(SI9b?q z`Pi%iLWI)3R>mbb_*{UmT7G`M)G=3FsTvYm^?xru)K62quX_sumn!%U?yqRRqZplYW0G1S9&(F7W(gxH6so47vmd5j)S`dB=G#ENKGA%TZ&WKr zRWc30J*lFtyZH}mzoFrAwL1$?yL!PrpBCB-AfLnZh5a1wPew->YX zb+R^sK4EjN(-#^9Jk*jNvHOKB z4Bap!-9m2qe=b*DS#97pyB&R3oaOuM?fpF6u4ZP%Q|{fbpRtI(F`d+x+FgS4g}-vx zGY^9BSGwLz>$h#YQTV{S$NyHncmIHS9@pHzk9Cvz5PmL6*4(biZ29X$V}%-yL%}wQ z+vb~v6gn=0P28XnkwxuLxW@QBLQ^H6qm~itg_MbM@61xsUl(x3AFp%=d;l0)GYSy7`aZmgD0CY$ zTc2^qSVLL^oqBRuCaATtXA#MQG<_>(1ED$QDgq`FO{!<`Xo~(V$9@cTI@30!4}4P8u&z47jK!k?*ZngY_u|>BhY% z@I0#u7`~t-<%1M)HNm}?ucRHUd+$|#4x*J67AcR2WCo3?C=wH8K?TS2MlXc?CCvIHUW>KWx(B$4|krnbN2u3VwITYd_ z3vkrd*Ve)Ku9-`di~Y_mWt+AOvr?{LeR{nEVM-dQNTW^xsF}k<5eTO`eSY=o+~NKOrlOJyQ`JDL zbfi{3Q)v-DOPtv(9LVI_NCOG&aRLQlvU}Q!ygheH^4a$dLM*}!EqZ6vIm5f8Pe)AtDntfTf@enR%!-%myM?i-)keKapMyhe^F=FX)1+^nkHdPjA5? z{xjwA^??5`05w3$zftoYtv>-IdxbpMy^kR^*Q-NOQ5eUF5{(A6iMr4`Ms%f{x{b?; z7{eF?IS(&38qgKBuw}i}n0SbTPKLg{j`?sml32FTcS8d&6@BpuPCsuLT~#bHJez9L`FX%8Q+U#iqM zF8Yrgdl9=kWk9^um%EJPi1A4zXf``s$a18Q!d2wiE27kK*g8Lb(1INOkF{8?M32-* z-Ok1XqSz}CqOD_B`R|kAB^LpC+zdK?L<}?h8HUMx%LI(8b&mJ&7l(6cEIiHgk7_e1 zin894_9Q5jP#V*_n4ex{iNcDqiT7;@l?s~B5)H6XxZl|L5{8Tpq_aZq;L|8b0$tY= zk5OA-@%1X&54GQVRKjhrc@Z0!m)!}tCYyQz>#L{UqAutHv-wI07eK&~H^e$osWe~E zqP;P9dryrjiuYB>`4HAux>Db|IwPoi4ODko5cgt*1?o@~L-i21ShF2&mN-y~R3eH` zcc~>^306C)BjoFXrwN{5kwV#xi)C!w1EUgW(aB4+Fw_Ap)V_+SibQPmKv|VGa29HU zp7G~Qoro_d=5&c?j(|idyaOsdvbYD8CDG5>nE-HgrSD#awX!xH3 zSThJ|8gwF7Yf6x=Y8*|(0t!lABF_U2%Hw@YUDhe_C&@KlKNbY(VhISJ<5?}I3Cp=c8OWf)W=cNA|KTP>Tf!m@ zON&D>9a9xl<3@zHGP>Ga5}k)SxQRQE0@tY$3{VVgB}Hh&oZb4|F0)?n>HycX#Stt?6d%m7UG*KjrLb8xT+5}AKPfi{2h3T!4< zYABuWf%@m}|EF9eS`uQ57yM44T=OU*r<0Y`_lBX!7BZvoW!t~PS+6M$>A+ex1uC~P z*QOx_N_od&J9}M~Y}8-=Mrc$<^xz%A)r_Sfg76uEzFVWz*Dr)5kk@+`*tB2(yPnGx zWVFS4HIZPQaLausVk!9JTdBX6E?q0*<(3qnZ>Yu0K$hKw`c5xYnisV6Ov}cH;`zQ; z8y!B8uuSr=Wt~FmeWhW#!X3nj7k^(!p{Au3iyn~b0&~An&x6d(60)_TMh7}6uRr2a z%{Svls?H;Z=9&Ku#cmn4YD-!ypy=jPW~bEvRZUx&&Nojm~TM#F7a&f9HX>C+7 zs!=OGW7E|nxs;3}GSLAwyn;G?&iVA)DL7P~VBB-}PQut(n@o1B(sZLqoMRCPqL1rZ z{Vj2hNpy`RB7MFK!d$G_%+|rtiNwbhPW9N`huE20-3>V&^>U;)@E{qN`+}lpAjI-7 zW+gZNe>E!h{A?W#aV!bdHlf&f-VqDeRqRW&B-dFKsNt@AmMSLg{AN#6+L3NE5*eRt zAf83kv5JKc4+P5Y3B#)(y6gz0y7Ris+~q9&vEJKp?Y!Y9-S65f@6+%`HT@!??WQ*R zv~DYy?IaC6R^$y7N3o@Guw@{jl)s^cRfI%xqK8%MVC&D?v8F1Q@ml`7EdIj}xbY8_#&b_jUJwpg8f}g%K2i!pk+oS<`LkHp99=^b z`xpmU{16);{TaeBZ(xl&UGb<~Ly?fC*ig`k zrxiglqCV@EHx{4)rBR?+i<52vkuZ$d5bPB)H<6KoZ6(Sc4qp$fi-dBDEQ&$8>TZV)r6LtrY@00EZ%D z$GkxX7o9b>Pun!*GkB(H6``#c&OYe9R~c6(fcgFV2!-8cIif z5vF=g+)d*5+>{_npOnV`Ma-riG65R+h59QU29$NuUV2o_KDYI7xZ5gXt>NvcX6tZ1 zw2)M&mals89$lxP@D0ZuSl@sgg34qZ#OaHVeXwl-qAb?4R(XGKL}xk52w$J|s9Xd= zA`CIJ!S2kNkFZ%%!TtgzlXdK{Idr`c~&tr<{m7W&BBAid|(e7 ze=Mzp98kG43KT^LB(O*-35;7m4OVI{OHG~XFsiw$hn5xUyRlF!X7Y)P8cY2#Aeq5{ z8WWd7uhc%)_i&-=Yk^3fPAZyZ_;^YRHswwl*_V>`c05K@ka>5&gpQTPV06msXS;%_ zv;LjU=aKc9?5OMFsF3FOPk@IT4n1iY)2vK}nz8ztrZ~;X#1tw6eC?KmsPJl#JJ7LM z3G|K8&NzBnegIBZO$JoLTh+YT1TCsHf{?ng7L1dxn>HI(wQJZh@=cg`u%}VhH8qI# zjPPB6wQ9GAg94@tSOLGGG$4+$ALI!L%}-eAjYeZMzS-|gq;psIgjUv`NJce?l?nFD z*P*irR3)n(zhm-E2o>T*EE^*<)Rnds+8Zw*Jq8<`eFpaG7q4>$^K}<|_^()utHjT9;;jN?lvIS&) z9wbH#VGQ`7eMRcrxX;HB@-}z_4zahl$wUq`qi0-vPK8oNU=cn_(rB~`;pHi8X9-Qm zA6KKZpb|-4dZ8mZ_+gw5B9=oVYsX;Pf(v5>S*~G4vwk7&4xWgUBO_YYj&y95zM zmx8BaVdwl|_-jO?)y?KwylP6A6~weKL%3X53So*s?@=p4tu?xv=!lyVM9nKx{YL}q z|~%PI@%7O_?K@aR{6;z9fW=Y-Th;1k-Z2K}OWQ zmT*plI=agX%V3;&eyzF)F+>}DT$8eHZPQfAcF3X4Kas4K=u!6f5Vh8W1g_bk^>n?N zwne~FOXvgPBw;>SY#>~5ijaQgMd8ZLt_Tz4(tPqzdHpT@YG>T}5xOQ)%Lr!=g2rS+ z1YacSH<%ozGIFSXn(-HzI3y=CV~y`B_a7!uP;7s2rbKe@Niu1mGH4-CN|WEhNCrth zfL7hA{+PpyoY$Rw=RCm~ROuoA0b*uYBmHVM?jDyeHF7RA`h+XwQzveRi(%8m(BHI| z329+~@$Dm^oVk;Izin~HA$|+Xhzw=5c10bh(fU<%%SNXDXPF3>}tUENv^F%0@&p+qNo3hrdG*{#KD znuUV8xvyC$k*k1CwGm3*(`YsVDpx8^o!+oxlSsbwpb!4cBO?i;Ys^OOTlr$WO5Nz$ zg}58-Gfm_ZWBHN+Vl)eyqp`-dcHFNIY6+GytOaD>=}7y#XLuOPTfsyNSvMEjx*GTN zQ$XC|t@FUJzdi`@(BaqjHFxl#A#~wsYCL>8u zNL0<{_1X|U1}Rh;Ndj%0-kiA_gWitvsM1H%5FkSf?k&to6=gdT{x(643@qVoMG)1e z>=&xSLNJewQD~2Dec2$6$jy>!m*=<>!O;*wO*|zvB-Tb}VV#2!_hlMI@-kWcVU_HU z7OLU|MRFp!e;F;>BUc5kxA0m9Y6ds7hKS#X80o3Pun(P}aM$;DAG< zCh}rffQQI>c~v=`uuGb-R)fYu4RoXpkdg#aEasj8Sy{YN9`^8B7Q^7ngPw@Z*||4) zi`stU1cq4=UyC>&J$esH?otiMkT#D>w)#E&ic3}8OKa=V^oMP!J&eeyifGv`GgW_KdpRg4u1{x~rC59i)bAAV1tA zk35?9n5Dpu!cl9?AuX1Tt52W(NT4R1ku@P+%Fm==xl&je70g_M+CpTz7Q$nnt7Y$> z`y`l(kA?UR250vuC~heb7$Yw8Yp1k zC=74$1E^@EOknmdkJdSAhm65lx@(=O-!4)6Z;5>;Z=eb7-o0k!M%TnlQyeH>r@N60 z_lQ^dbT2R@?=?Hz0DcG@x#cN1K-MQGA?ErjOO2c9A9roLSlE~UAqk3p8YPm!wsDwHFlq!=tNaal2%Q8RX)-cf6nOPuZRruGd zC;@_;7R97E;-n(!GgWMaevED=R#Y|gJ|pwd*JPKjWiCU2DOOOOn`Bmm;eG`vck~dj zP&Oe;##X8L!SQFN^*|jwRKr;4hvqFJoDs4TT6)*%otfq`i`pWgRu+V8!Q-skUJ(TJ zB21E9F*7{fI7UmUpGF9>gQP$fdEulEF5>FW&%Nz3=`%%PlQCFx)+530SrqG#Y*PGe z8nv!_YnGCrNRPRwbfApYoa)TX%9+(C7AG{~-`L{1Wl}E6n$o~tYc?+fjQEken`@l(Z>x9|Dp97YA;6bJ{iaq@;=5eu6U%UQoOGk8qcCzSx2S ziuv@KuzfJ3-9ycag0zryGV!D9m&hG5*1a7;I0R9Zw7GJ|I$Zm&8StuRZuZ9 zn|CZQ+ELF=HUlSD=txjfE~2iSohy8oaP7pw2U-(>m0=Or1!O4mDM%u~fAR9b*1_!>a>RiB z_l$s@Qd5R6+JTI zwd{nePr?_&NeUBHYEZhzbnxfdX(X|mtG5%e-fVE8B=ju4sz_HIy2mFv*!0VzS=g7E zmkXK7Ev#i(LKLFSw4r-4d|%}=00)mjE6yPDG4d8yV!$~a!J*2BUsVkwQyF*^g#Qk`Kl32BQ}p=0~Lx6+<%ujo^^$v zWSHDD!L}nKu&;RaTXMLH} z9^>m3v-PJRXhim|%V@Th&#X)-tIpW-Psh`}FS?m2E@IQ~7pz@#8@FK9;0eXlI{A)n zT~$&NG+`@!z=6`@ZOg9Oy(HCdFZ-Hk|D1eTcQxs0mpDu;%Z;~bV_s~XD1)Y&_$K^< z$Q9#XA+K5Y3ZfNkTGW5`d;$Vx0U6g9YO{>Dl8U0p2i>c`zvj_9C-Q)5;KX~tL2>hi zx!Cz1tMvu!UOjXs8WuMqV2tb{%}SMLj_*%Es_;AzC@4brKS6wa3??x=BV%=6 zwrY!&&=0ch3%}KN4$LikPJe!}aqT>_?4Z%U&EwI<4jRjtgmzDTh0|&0@C+YK4xR@e zhqM*i5}9^l-4(VSDm=7jm>yKp(i*!EBDY^nf=0m%YSj;3n#F>g;6Si&U~tZ2L9RxH z_~8g^eG%EuFxEA+&UfF?mTMC*(GqYumHr#$48N8Ce))1M7$R>tx_2Z^?mZy&y$@N6 zEF%o~MWo7no|{C;<#O}`g^SD;Hc&Cmm&`uMCx_1#%#w%6X7QbQ>`WXpZl-6hW3GeZ zL;kb<_m=%9fqw0bmbsZ~3n*Y3nMCb8#CPnlzgHqtaCG0-d2zVuQ#~^+9_8SGH2d$d zPZ2Y?b+g#gTCy5w{9#MXt*Wk(ks?N~IA6zixC%iNx+h0e@=-@td~gE!Q7 z)RS!SXj#btdgiiRPS^3HN#vCWtvNf~ZWSN2dc6m%j%_yr2asj-I4o$bgUn=R<5FJ| zncZp#!`txZ9>z{kHj+toXqiJ!(SucTouk*9&2V zQ5-QH$G(uYawuCnmPHk@@h@TF4g9_;n>1Xzexcl&puger2MowQv(*ru&Ex31A=qT- zOT0~YV0y2-A;5hU3m+Hx&7)Uq!~4>$7(PF~wRLQ0fIMPS+h>zmQ;Uz5`$&Ua2R`-d zc_c$ps#HkIy6M)9AIxA;tST9kN|Ujq{nvKcuZyaplwi6U0Od9_ijAyl8I!hpl74Gf z#5c=;b_7+~z*XzBRt{%t$Frn;kE!iGRg%>6DvGlN&)Q4<)R4{(0VyAKs>1eVtLVqyw?Nh1+m_UC7w4Km_&lyKiC0m_+Kj;!{X?i|&oad{!XEAbmgNpt`IF4sER zcewLxJ9k?=`E%B+-35t^3Ys<(Ng{jULVI4)c4me}n`c@r8(J;*7`5!@q$lm}?N7)v zQ5~eSU4>ntGocTvvw+?}Sprl%gbW`f@7HT(JIA|cS{M9sRYrE}RQLF{*hE zk+O9jtqUwKYH_p>IWysJYBJzbH?lf=$Q-YTeh?G>AS$WfrImqhdd#WDRU2menp{h; zfM2_%=cm%<58e6o{y~CByYOPZZtUUY{DJNHifwOp{2eX)X@&${HTTQT{j(s)?~hMU zJ=?Z%=s>g7lRWe1U!Ts_4AgWHbA7hQ^t81*Jx$kY+7+J0YpB(;9sc73-k1UZiC%+u z7f3NYz4|M6JVvWFXLZargeqc4k5`VZijBP^U5*ReGVu->b>kQ-=mnI9m4zw23`0!J zg3RsJs6;v4M;)o{K~aFZQM87IZ3dCOufEs6d3uhjD;ri}F7li`NwHHdyATHjtC zFi{P8nr7zMb5l(o)zE+}dvcr8WH3u*db7!ieKl%0u7gl#^c|@(6h&a& zNOJRAK!2pxWy0M`B{BsfBwlE~%HY6K;CiH)Sr>nR21&0OI!t`jpN>Tr5hjXo=eWI>{6C)e>qVAhXBO~^_jwgDj(FL> z67Z!*yA6h<-bF=tHBK==$X(brxNYlZaS4ndD29nPU-%W7*=i7|1siv5o!Pppzjyxt zr+qZPK3P9Ekv@c`Gpn=YO=i8>iVzr@JNifaf126WDs&>5$&~(x*x%CX%-VUi*mtX8 zYjdm8y6vK?=1M1qu`Qvass=a6Lr80w88DOtB`Yyh)#L6l5n9kCQsMd91Wwe&J0Fn> z?5x;lusRz5oxQXH-9R!1+n1#8UN^5PH68s&($*Ojg{d6UrstO+gre%SNrq*UrzTS& zEHzZtWA8B#IvT*YRl6B7UM`fTXyQp4G!nmr(jHhLreLhnQ)pm;of-cO@jm22LM>lV zuhR*umM<%&2$&+JARK`&F5PJo&IFL@Au_Mp}aw@285{5&?t=N)UaU^6+@*G z2;iBaPLb4bt~ZJd$nomeSv*%IR4*QLk=bO+3u_$AqoHdtWqp+CXQfp)5_bz;z8cY{ z2#VyjJVAqCLJhS%xtqdXCiN=%lB-bD=uclK>0686cLgXWH|ZVnT8hvk;Bj-yNuqMP zXt8hdUwfSLtmsmT_(f=qB22r%!c0$$Q}XuzC1fB`LOPMkqhK*SDyax?TrJUbbr+SK z$~Z;y(Sa?RT6s{J zh>mCcU>rYs04W=fQmpM8&EA zWCko!)|CM-4u2RJR&IdYW)w%cC@2rQ zQNg2-6+9M8$s<#g_7dLxOG0gR72Y4sZY0nIV(|+9D?j+{<9NIpn57YCh|QUOI^%S4 z<=T$|03x6tJxIidGcHS@aaVCyZtE^LKFm!A|M;a0?NBEynpXt9uv-%}?h|U6uvK5eF0xS}ujEt9 z1&u17VrNh{Eq znO-zsFTs`2^NUb4S|N(7YUD{8^z!YZ!2$$5E5J$Cxhq;5xT)-aP)lLQb#dmV5NYBS z{>9t!@&%Q6fM5F0DQtJ-nyDg+fT@`dSrScuojOCAn>GjWWK!9GcJVb@lzwJ;Q@j~h zOw5hOI4}{qDo&6A$mB3^RAmW5K`Dt8;EIG$JvM4RP&da}p^Id2Xjqz}46efScaMiP zcBTC<%bS@E*!OkSSZvFSTS|8)isYpttH9Y)Ru;zw7(?nZk+_4YssB-kbtN1!3SNdG zeNFwtziAXz*V2{Baw0v8hD?#cXUsnap){Tn5}2gC1vzyyKs$FW#GaRJ`|9v=+Wc*u zHJy(W!SRqG!)|Z|Qj{SwRFxQNGip<-2UV;fCasC)e8aKGCj*^Swo<_ts{>t%P%=BpCmcq2f)iqDDLU=1{Zai?P%WtRWjfzf7!ub=R zi6>V%Yl@&HGmyCC`1f%dZSfRXD{w-EnPaHVam#p-HKoYpnYj4Fu-GdgcH3A4SR|2& zsFO^su)2e7rBs64c1>2l2M9{GJ*7zPwTHT9nY0r=(GSXc_U)pE53Ku5#dnW%=?Y`N zs3z?Y-8wkQI`1Xs3#@ZPsq%WZv@Sq5AP<+N;B`c~g0*NFrjv_7+1_mpD!H{H-M<{P ziUzi{R=-icTnr^>h!WW%?lNp84}+%snD*m%PcJW7r0HCGXqGp$rTu7X|6*Yw@XD{z z-1x}v7k%ssHe{FKopQ<{rJlCF% z_anUE=v5t#z?woh3=jv>mk!GWy19uiQ>;4(@iP*Eo2ukQKGLTvjid5vbiLe*7DUot znVH2XzN&>SuhWmo!{sS>Jy9-aFJ6u96ksrA5jEo9FqCftXS?6S1Ak0MO~>QJb@AY1 z%1t1KO!-_5E*N|nzSOE^xQX7auq_mLif3=!3ZOKBVAU-xHB@ubNg+3qME5ndRKxr+ zyst6X_gsZPhWlRQ^))XhE%#l}t8xYgx*Fda|DSDxIrTkd zxtEpZH%RiPmDZuQRc?(uZ-*|2!TB(8l;6{j?2QU7tMNZxNf{|VBQP31+@1H6u=d^7TEN3Ai*cv&gD_LWHMz><@!awfu81w z%$jcMK%`4?DH!+OMFQUefoqY!5Fu{X7>ULy%CBfDH%%%T4R{iV%aCmN@twhX7P&sB z_4CrzsGv5NL;yO{gT`&8bUOK~KqI@ZyW#!9CC-R?$ z*F50^7+iP}URJBEB(jo=%QXU+DiJ*Et3rGo6MHSS!p>q@1{w$GfEAnNx-Nr3*S%Su zsjI=9%(amDI!TsQj)lwRFtm=$&$aBV#cJ^Yz(VED!)z8dg{yG}|d z)!x|t!RYl_HA&;*;{br18JsgDP`8*(VneazhZ9t%&eSWFnFe*CDETH6eB93#4%M4r z;}7euP~7e4t}LVjqQZRFSsyFxH3G{6OHqJW{F_&CY8mjl?+HR@8=V2?n+Gi2INiB8 zD6X0xe!hbPW+Z)bb(hho=<1P~%sp~>Z+hZ|J$fM%Dg<8ExypPgeC`u5b8Fn3oJnP$ zmza%gJjGCrP3Jeq?8TOnvLkWiXK}Hc=sa7aFSznU+s1Ah;Ppr+*thgDy1mU|my$Pq z|EvkZv<=I(hTU*jZr!DKxh-U_S(-E1Z4SMe3Me1q^ln)`hd0gp`Tp%*iib ze>n-CeDV6lq~PsovzeDEpA-%Sb&~peQ>u8K^P2UVXdnP{@i4&3UpXg^Z}Q&VggVjB zJfPQsMJX5KOs&22?fCYQjqSGtlh{cfpxk6*U?z)EF2bd^R6fz@#}UCZ|NihG@%=yhbQ~|6 zeGIHS1q1{IQLR}}#Y{)apTbkDV_CS-()=s_^pe`TQ&&wCMX~N*bgY@ID$;(Eni)VD z`&YE}7xWOT{R_nvMaLqhbQzP?3ZQFEJlxID1_R=KC}X~Qe{aNF`;=Pxrx<66@Tb^{ zF+3n>#h{n<56Uf;t=g@29hKHBMZn}}j6O_?Kq5!rats=tEldTJv-k7il0zC1bQKF&5dJV~?ebmgg%nGaoj#Aa zhp$wC2DP9`!P_y8qM`J-m{)M7qzsN0KO$EO8M&;A6HSmhbme4nr2t!39w^T7J}~Wk z(0men^yVCeX{@vhL7xfn0p*iWihMq}Yeb-KHk;Kg6L-bMu%rEp#713~L8;WI(NV85 zHUS4?q8`1Kqva#&(j#xGI87#WR*K~aEC{;$fWPtJ;^OLKHggRn{ z#~nk&ei{L)`HZ{T5X%%Whzwl?QbqMf)?h0{h)m26k)Z0&IIE4ZOg@c7*Ht1l_@)mt z*x}7~1WkY5A;V3#OX560U#}U;o%_2XvfR|g6s4=`#8L7XS4_kU zhW|u#F81}jRpp(9xJP3F0Kf+3-%Ni!%emRk-JJ=HP}Vu-o{EC%f<5P%vo+NX)q}pq zhDIpWgGcI*<)=CEAn{t%(ds?#+ktEAA3~FB&tI6l@NLuX;opW1xAOwZCxb`SEqA2Z zp>@A`AnhoC{Tj4SQqSVonMji@Z(7hK6ThyGrL9z|m`pZ_#9%X3Xuw%b`!}~@BSTAv zhV+)nb{Z<<+bvnPrsh`9ubw<=CIeTN3Lpoeo+f<^r=UG*e?T5{Vx6D`l(YDm zHctN2v+9_vm{eEq*tB%F0zPp&%a`ef%zwHy%Us^u*iild%h37_O=adu1J#FfR~ViQ zC0JZ7#gInus&gHGT>Iozci#E>$lzyj% z`IcL2`qInJW_Z$kzdDz7WS4zpE2e?3!H|DOk@%z&`mr&Y!6hQnL|B<}g&d?#1M`k* z!eNNz>jasMq>vAQHQQ&5aI_SSLd%RWBGCYI289*`f(X`rnVkF>0(sN_<9>j^jPrz+ z;Y}YlwR@bNq4F*{x0=a8qb$uc3+TFZo`GfUbGM~02y45nCOl60ikG^DkO7Ak;I|}w zmSHM8dgLg9M^XfkrWf76pi@k6+fiBQ?P@W$+f7AQ1VxJ#W5VbujZyRXeM~WNXc}#+dZ>F(y)_#mZ+@JIt zru=bHG(nt&Lqge5^1j;b7N0>MP)M4m?1*VRQcH9aV`nT{nWUa*Yw(^nLiw_>L* zD=v-kJ^XG_UhyKaCS`a@ae&mO$ll{ru4|6oq_0t9k@lEsT`sT$G`%n#RdEWm?}g@# z=QQ-vJa&rwZfVBSVaRE7jymCW5b~q7)U@tpn}ecU?gV_AG>gBOW7McK;95UTrjw@^ z61=1*NE=b?gIKSKt7^460|Vc z)4Sk5vO+u}IvljHy=TcDw^=)NGsNu*zZve%4{{l`s5|rNw^RE3j`AP>3p3wN{hmL~ z{oar~!eJo)X2dHuj&wFXp8717izRA7EDeQIw?~c)OSl1KeKL%NU0Cq%5MLF4NrnjG z%@UKlXFp9&yZOs-?(i?Ds3h3k?x2$D(fS@bR`}{DpH;}9c{>MR4a)Ai+XY+>jr>Ww z*Q;ZER>3M?nKgZ{L3_!}iJOjC3yX8Mwb)g-vAU6s!C?^a^l}{i)Z!!SIlswap3(Y0 z?ax})Akn&P(Zeij-VTd(9vc+1!?K?C!>nkRO`7K+45BII(p9NtQzQnzeT zhsJ(I&JNd|*|+(YFj`ij)krG3m=<=Mn8jiUIQ;(qdR4zWYE{){i(5OqHku%lMjFB1-Q-QMnu;Rz($D6d-{gG$=xpukBA8EiYT@eQo~t~- z{Gsz-R!O7P7P&YD5j=V?Sf~fQ^UAbi6zStocgX6g)$aI2DE=`ZMoQ8rQTiDCO0_}U z+ALN>l7aQVveP6Qoe6sGJY`)<;uvwW3$yDO>t@MlZVp*ap1sO`2gQ}t ztG&J-+D0;*pk5_1E27oW=F(GH`G>0xf z)6iv13cMYwEzwqwLrvb_9nl3%9D^=fm6g9?yCfrfx4}7Gbn2^e>l)?IDpj#XBEY|I z`Js&Tx-Vx#dFZY!q17vnZ=5%D0Acnw6^A4l1-VwiSCI0!$f#%WxIDj7Qw|CjY*e|$ z2tQX-j!|#M#px2`n34T}T~*xFWfswx0Vndm!QcZBBaf5GmNs(J{6hEUk?@A`^mxU_ zkw)L;saCd}E75RcKxF1xXxEwP=BBPf`sH%{!~EHjV$Y5PMyF%WkUL!zuV#eGs!a-v zJ*BH6=i!v5PA99huTgJbsVTE5*l#!adelsgtBc`O4kiCWte-4Npz&mA1YD3NmU$*- zxh?N`?NM6DZ!D@k?kpg3aeUmp*%BKKDRZrs2P8d0-D|JdRnyb zHXuecn)GpqD`d*xW8jSG2r{1?mz;MaKA{G>Bx8-+4B+{@&6({_wyhnOyLQnoQ42q@{qFut31>Io&KtqPc)~_^ zJF1%T+a_U=VIxMD#iH`e$6w$TScWFO2c>1yMb)7jujBxc3A=fCB?71|Reqyo0o&c>Nb70ivtW*5-bZicu*gJ{Mm z9KSl%aF|RPN7BBioj!gumJ?qeP4TnhrWU3mSxGGy^S;4gr-El^6(!VSC^;L)uBHFy zJXo?nRHomNUNgovVvVTJ^i(*hr7vlp097?d(QG}Po50dq#m#C z%IB;15bTz^dAwaI_d{IV?khTk>QC#V0*h}l;M_5Y&NZa6zecia%xfq!ve zwkB7fKkyRR>V&TgD#`{H6}$&E{~GD_TYtL2ZWo+~(kl=X)=HgBs@G}P#bSb3d&a$K z9@e!kfOK?2MZZ@sW^R&7ClIQ2+N}pj0=<6qrx>!J&#z=xeOQv#S~t9*GgTY%+sz{M zM*o%((WG3&<;f*{ky0a7-jPS7P_r*xw&c&|JXm+wg zr%h?(<|(rqH}e!pLvc{5=c<$T#1Ti!JuOcrgwHif-;)Z(Jqerc^%_!Jjb|8$H+(Vl zu3Q2|qhswYX+9j@*$J}2ri4-%M^m$VAz$|^7skJ(FP@h(SYCl#R@TKb_io#LaH{Y8 z=9u?bQODEN?}SlI$#RZVQMs;4A|(^W0yFU=1; zb9daTHPk)+9CUawA7}ea_WAgPtn{C1Hxd1`V=?uNi66ryeK;xwg(8x#HljDkb)9)zPK!j!$&56S;~?EC)mqaX`r6O zQdW9w(C=l1D(>-L*R9VNHZQtZs|F!nH^%EppJ_h#L;W}Pn{VvuUUcQ=X{Zti@{jLb znzh6ew?U+0C%#$!?q_--*h=MM_VW97X71E#u73@0BWQLX@g#9@5m35Q?$+yD1Prde zzB(b8-IRVJi_C;IV<)%R_{rwwQ3~;cyEculI6ZKB3GM1{YS_`^U-3!W$PVU)x;l|Y zVGg3$0yI*=;D}Zs7HFl$Q6!NxR^|#XLF+Bb$=l=KjzORq>CaGeGL`rOG%@~g95oIj zF9tyg3;I|WmvLkqLO~JwL!7N%tDmx;mS8#iO-H#Mb|VCm;9++Ub92 z;*UK9b2d9&bA{ieYn$t_3R90z-lSFwP5>rFJ$4{ncg;xEQJy|4c=D5$MB$i{x`m2L zNKJPJ%ymrl-)mBg-;cZcGVuLq-trlZdVPm zF)1ZwDK>bloZOXi*4D`mq?CM^92?%PpvscU|DyY-edgbRg%E_IGZq>w{6Z`4*;euB+tdO4Dt5x*3Uj zk!|Sf@1xDVky0p-H)}FZu3F#wSBw6{_rSgV2GeWHqOq>aw#&y0j!SLQ<%gQnAjvFg z8HJrMmhmd7aeoTefmm*N>w7DI+6?uLs->~8Pt-!;U|fN&(xp$ zEld^@%}?*l>qX%**SOTsV^MHA7V7C&F)ot9otwGThbUl* zsfAvuw4kxt%_UUEU{eG0V)rP>Ol;<(H&`2s08eFXt%gggITcx4_KLj0B3ndRzhgG+ zan)>uL|KG3kAYOzs`N17p&8!1_=5lZ^O%{rKPwuE*@ErP*goN(n9At+{MBJBtVmU? zuwv#rfVH*0?_8=0hKcAci1WjCB>#?c~1p(e1 z_nwLEvj5vE(*@{fgbNL>g3KsZBaSYRhyeaqe#Yl^V4|a{s`4ZegZ_syb3{jBA?A3z z#Th!NT2Bx!Tx;Yp;Jli3!62@GVwbMqs`Bb6GHokQ)~Gj3iD_+X%OrH70QbIu$uC;t z8uVs_RaC9gtz-Gp`IbSjpGz=jq>u6q`PnA+zamAbsMyeWn5g(aFMF}OVc2wim(p}o zyl>B-ROPr&>s9WWqLktpa2ynR^+$JD&X2eJJeItIEZTY8HXLVj;6RY8VDN<{pC7OJ z^3(o;b~FM@PrpRQ+nbY%s}IMADH$VeNZ4>1E*PvWdL!fc2c9~L^lYZ5nQ4>tro155 z7kiROOaTs=_6t{bYYV!>iKTMd@r2_F8i^#3(`VymR~m`& z(#HNEL5G@CmX8%KWGy(ArIv!cOkqF7{b5o947Nmh!R~0|AU<=pYhG?o%_EnJN%D))kOB)>fhzz3&%o^2Mewtr*e4{n zK82X0Rvgb6Rr-8XT<-=)dM-y~b2; zDP0qQbd75s>&ITOUqE&RsQs*feErTj;0R!D`4o{~K^EU&D3WRAWCg(g<%l`SP$#M4 z^BZ(QLp2OJ2TPOZ5CjS}lPO^VU!h`_6#_y2&tG42iXv+=XHBEKc!R`6KtcX%udmVk z5vILeY+FZ_N^C5#($RO zbrr!M%Ti)am39bz$u@G{MH1-jR=gJ820pU#*#h;oKNR3D7uS#QQvpjd91kW7||XmqKF zOqK?urG%7N`^@~zcuG%`+H3`aMzq}v`QOv>Iz{bvjcd`_;|WbXL4#h)sjucM-4yme zs7alqp+k^P*dx<$c`_}7A=U7B5)G65!OG~;Lh;1O7G)SFx71!syp$c>jdg%tI;9c1lDO$kdtT^MeL=^k{$|f2n#nNz$qsTUV(;$A3KPU%+fG468 z-6q?M`?~1NLxG zC0d7{PWKws>3zL#iBA z(-YGd92c5eRO`^tHcCq=#Pcc*;lPMzdWLqHt;B4~++g>$w&dnqx7+OK3G_wVMTJrk zid*`hT0$ZT3)VhKPBi1ifROq3M@X?2kz5Z>QUPuLfAO`_oSd-(hJpgeb&Tam3AO)z zL=@EtljL<$4k;%G&tlmIl5#jQMV&CQt_bb{f;Mt1rActk%vb&;KNoiZ-=rw~#LjoS z`gUa@clOm*hys_y$JP`j!NVo-sYsy~N(3iMe%2S@utFi8AQIqkWG;jy~K-tuzBvsuFJk(G*{UznlxwZ>uE+Cx06|EpMt zf%lP+lEl_ZS>FKPs;t1WEi4Mk!Dmfv!Cf72%U3a2u2zOk+MgW8tZT@NCou#_gt1Lp zFfapeeeKzHjJA8QY-n=G=atOw#q3yU8*3{=?>*jE>0q<+TAB7#fJM4*ttdpAI4$E? zQqR6t@QQW{ftAA%3OqGr>Cnz&yQ|apOque@u1F%S3ad(YyO-pARU9f|lh9~3 znMmMKkw^}O!k5l_mS_+EkMv#Hra!b415rofNbDVWv$-8FwsS~C9n1|AqZqt&A6liZ zMPt1gD44kV$0rBHQnq2S=TczjvGkWhA`&SiFz5mT66Hd4#-YnQo93#`d#1Ne=GISC zgS`IV7V{Y7*b*)UfUU(-WX@l_vRA3tn3<`vUZvUGvjIIkR)^AJFd%`=cHZ^E@h0=k zy}sxeRC7y6#+tinL|}Xs!GRRj@Kf0RLYtxr%`yGRl>&&h6_pj_6snV+q$!E!7t63!vy%x=N0+2qPsGdQkJhQlxd`;A+d!L8+q zkq8(+Rj4Z1IwNjf<=K6d);H)Kni$IV!sib}?Kn_BRPRN9bv(Nwm(9-WWaOx~Ktq{z z=St#fYzYdUrbOD$gL@WQi7VP^lt(9nh@2d@K;&tpXtwM>74r3+#C28E%} z?5d*0**|3`(Zi$y3JT4wK_*G5s8kW1&hMD_L}?GKCQ-@;{?O_TWG$H^v-jXLGmMsY zqa#T=Nf-Rgg7gNoR@aCYoB$#2`tu3J{6`{@ot6S)BRBg}ZX78ma5&Q0EF-WPk1x~U zC}uT*DWyY8q>JS*>r9!-K8r*MnRPfFiDc7HZ1!6y^evnH6BHi%@5`svVRY`lopsmbkPe;R z%G*D3iX9xT296E9ZGq~@L~t|~0XZIU-$jR!|MVVhcfbT;6P>`1p{k>@b;*c55hxXn zpJDz?r{y_wDC0VwzCiy}xUjVP= zler_4yrY@5d!$>q_EF{7X)YySkZ$$}C|q9rw)tp64o9PPaEKJkbc-iEye=WJH+;P> z3A+AkAn>ac=odYyYfxJ9u0rb56SO=g9_h&+Tm(fJbQiqYa4I z#;sy8kti17@uD0oF+P?QS4c%`yzE6aSphyT2c>y4g*0cpoF6u8k%B^NI1#H_y#ry} zOA8EvlA<>6rghVEg-hu-Zw>I@)IPm#ddNLWLWiUq*3BN=5EAQHP&0240KhiWJCWpf z5Qy!L5Y5wETYx3b7x)b8^TgO57yGB41ok_P^buweRh+DllxTtYvv~XKUbaPSaNlkjOk9WvdT)g-J|er6Smgi5vuEUdTyIWFt~p zNr{-$bYbKML(eWNv7GRSMLvQlJ}ed$H52siCOJR#)S*A0-`o`UDzP$c3i;)BM}^3) zIYh?pCYd0KL~^P8_`$GQdHq2BMzl#5eYS8k6EE;}OR@V_-T7 z2P|xK88Xlj-w50x5Fl42VVHPs!eJJ^J%;)V}iQ{$n=gAg>c zW5sWQVG$v_ZV#YuPp;UTI!*rZ_O{C7H&FO)+wpp)EU?H~Y*{(j%T835n8ECeS?ny5 z1=cf;yKPjSX63@-K0~=U^l-uLp9Z$O|7Z=TD^DO;UgoS6t|*k!%RYujl?}XDmCiEZ za<`znhW$}o>`6w3g06^>n3bA?f7uE zbwyNwHOkAbj;XRjM$XN;ZBJFszFNSmfMdJjmges)@d@=gvtQ#fkwXt0giZzh6nmg0aw z6`~h@e5Y2TfADVM%1>%fviADJvJ*MM45g9}<0lfH4OWTvf$l-ZY(};&J2)ho^o%gk zrH!earA5vX>&ij9X3Ul)W-$9w^?|2a)=awVNeD6|V0!t@8LUbL6 zqyJ0l*R=D$r9~m9klBHqHkB6rYwG!5Qg>#fz%8cMtX8Mjsdo~E=~_`W*EUe2PD3{x z%MfbFT|esIDZewc$!EXYx1TfgPXFS-n;ejV@dPiYGJa_?0x~d#{3A$7X+_}-HT~>n zhiXT@c#AO4P^({c-g#cX+EnWnj*1IZvzs0EpkilnB3k1s$jFVQoo22f(4`wZ$IwxsX=>W>TSsKTy*L^EvQmHalUsl6KC%honE)SJ9 zRb5fe>K)h+Ehg|c+}UtnOvF>d@(fQrI>TzY(klk-{P$q?i%(j+RC3O;W}TS|<_5yvu&4#+=XAXMeqMb)oc69?h5>BGq(rOr<8<{Xd#b z^59+mrro`r$k+HF1NwcMw+BnU+P!>m`1>9XK5SFbZQ+-45}pVo$1fq+L;5;iG`FzbEN8x~&o zpS}!m!Ho4X-8e%#UTCjAk0F1HBF=)dPz{Erl!2P|tjll^%i4ffD7nDB?GU;u=B z;qW@hkLY0LcNja7WTVqbb~}kK&t-H}x)^eL4v}OJ*3Tgx;bK&F{!<< z4$o+=7W5Z#5QR_0@Wpi;d!E@WPNA?lz!p2@`}~KOHRL9d+=&S_L}E?C+=LQ|Fj1+5 zOu#B|A7>IYc|>AfVnQ{ERGl!Gg%%AFBu*JwswY96NPZ(dxbiQIJJCm+$*K8zcx{;T zY*yOYM~@7q$B)iPY7Kz|rJ%soVOh_*eD=c%Q(Swyz^iI-faOGM!|Ak#5A~+Uk5kVE zhRFE78Ce?%pLGy?gmC1Cr=<+o%6!ZNAzqLt1*C7p@W7RDio0JeU~T|TNH#4!K!S_a6Cofexy^`ur z8qCUwjtYmvw^fIYL+cJ;EaS%DQZay2Gl&mx4TE^#$MMZNK%WPhL=8jz! zZ=o3xmwBl+lF|RLs`_SIbj|h0l>=$%0x{>?->*N3%oDTNJPG-q!j(FOL(wVsq4_2f zN1UThH6{p?aRfyUoRjG_N{MWpD7mSsc%eQy%!1%(WW!6^qQmw7iPr)_tOV>2TPwD` zE>D2+P!#5K_YFIeXrNH3hC-y+Ds6h`d)OrXVHwk_5k8)%%1aY5>fO8d2}&Z^M0kSrY+ltsQ`wj77E~5L}oMyy78PUmcpk=!Z&<=DSh+$*bUcC_zs4n zz>BA>mg($lAg8Sk$5dwKR8Ed{=K7PPVz%`!F0V8;0mm}l8&W0-<;3IF(>!lQ8edx?KqPrN9$Yi#KlWF zC3)?8ROwRIAzD&VOiXbS&6l@ieuJ@JQX<(%D3t{Kkbi(}nE%$Z-LmuV>C?zt#Vn2$KP8^|qIZ!c>!Z{E8FcYMwFI~JX z-lnC({tmrMZCmq*3?4J5`(S~d7yAE$42V>rbglz#PHI28GKb^f9EkH5> zWw*-AW$~uBb8!Q;K;Eat|E@YREMou@^g}=lG`tVA0tp%-k|n~iiIzLQE$@@Oc-Xw_ zV^{n^$CdNy{k9Uq?$aw&JAQ(IO9uG~oC`??ye}%uAzQ2gEpG>X2FgMPY$OEnqB87C zcG{gRqbxJa+6H(ykJ+1r>Q*o1Tzh(Lk^Y1(8>UF|0~N zXz>{H1@1AX%W3DXN`B%0$!u@=N46pywL-Os%T(e)?SpRFx*9++o2kGL-9@LUD{2`W z6S?3G4I2%Q{qVo(y96#3tnDBQcrTpo)M}s=pBv&oYB$xCt4Sc zT`6Wq#f2pDB$29c__`=|e46XqGgf&(kM7}RtV?B{{#HWAVdOe_)PskV6!%q%VSNvB zl`QLO@Es_4wUu?>Au5qCvdTPJMh=TZ3gf?4t-2?zn8G! zq34ti#M~(59(^=il9Rhjg;?>SXZN>1t0@Ty-4CH^N<;2u8OXU--d@^Wi{zXe&V_RS z5ZPyRazt5RAOr#gXNm6Lpk)8+xM|>ILD0I#;p&xi9U@3|;cv-`b+%#3AlhBR`!(+a zWxBF3axEuvHHta>>Gp6890ZQ>zDXK$3Swgg(b0xJWr*&+7#-N)zs_O{a;>;~4q0-I(09H5Q-c^V z{y#v96+SR>2~?AR8+ZTx;M23zG$ zFk(B9&rLY!~f*qoXhpIVTawjLf_>U!E*lawhR~?p%(IHDJ=l z;=ad^j&1l;w6$L5e;zxyiD83rNrrV80mtfA5t;EK$|c#QYsB_6aZCc-$fg~Q`H1b6 zXGBNwKm9?RyOq}>_8gdqJmZ2uwx~H%X-*Au-YiFbJFShGft|H;#S5Nj&W0DZj_L*( zV^ofr2+U@pSvd$Usa#PwCV8;CcJeXMCA*1Zf|(c}Jhwwfr7#f*WQ#h}S!ZfE^JX*Z zVa@Eq6H#?J#&&Qr22HfHrmXMVUWh_8-u%|}-a;Xg2xLYE^Rd@CBcPHV0$p)txeGe~ z(eJ~#vw8g#zxYk1%>Q(mkQUf;U?M6QnUUFrx|7P;hC8iWQj0EeofU(di2^WuT^K(% z_IClihmkqg(NQV>r)O?7uSM)RFcC=vG9xnsJGSOeT#54}R3{gr%ib6(6%D$Jg}xF8hYQ%s~*X zY`F;vk+cYXrW|X8!F=>~&Pb@F;l<$s2Uy%@<*|S0&%!xPULVCLKC`_Q2zkEhG9j&D z!-%uVU}; zt$1CIb>W954xWwTMW*W)oPNy?G(6&*kq7J;mglOFG$5xn$LBuhd1A-$`!xBgXl$;3 zEoepkhAa8&e`7OE+kx!MThSK{y(&Lid&S|&6g%A=xY6xj)H1tZ6jzpS%!b@*7Jmk` z>u|9x1Yq4R=NMM&eD#=15PL(U5k}R|a znzhp;dX`oMvU4sL9VZ;yG{_Bdlu?FVIG{16GM!Mcn`ex%PvMZvZK7AZYbRfn`#lAJ;~cpKS_+wwKqXmFduO%R(Eet2bueS1*BQ(w+Sz1Ne6sa_ z1^ttbOfZVd*^0bDCJ+}@|0=~Apf?vyoihsx@gWsAI%{$dwEnu^m2*9Ly%BGDMPQONUEmkDVN8@7xN>WXst}#DV7a8`Sny;;j^&QV-Y7i}j?5eswbGE$JV#Ah^;IK}WZG)2-nCP{H zg}Fe^U-$*HHQKcF=4dI7>lt;}ImC)Z<_q}S#{vVoUt=zcdgVb!OLkQ~fOCU+ zt;L2dBY|Dlt1~W*ELJMApp8>$V+|YMtWjM%%^VXwODm#xjJ#13%{k%NrZLa9EeH zGy<_wkp|J5i-(=F4vNFts~F#pmroa@Z%jd;sD3VFWjG9j&D!1gYD7C25?CHE95#!hSVbi&*nu<_4KSd`+!| zR*E%1Z!Wx@vjK|3y7XG}JA0CBfFkb=&bQF7`UA|9<+))#Xwa8<ZT0R>vY8pFA zh&CL4K+Z>iPX)_>pMmK=iLuC`qOpvoQwx?Kg%x3`7*-qLRW)wxkF z)!n6iS}Cs#nzg*yx7%da9c$CnjS;+qK$*tV zvJa>i>QQyA>!p7Jppo!>^D&q)t{XK2zY=+7_nq`-cqf~j`#savkSck8qx z9j>Tbv!xF5IX*vKFL8%uKIbzII=YD6RyON`gu#i1`;9cvWIcB}{_h8I?eL-HqO!Ah zeI?!-#|0k_Yz}+frfSL)MnWQXpAeuGtmnYJ|uXsg0+Ec`M6 z&7%VE)9>GWzBK?n)!FRb0&sp3sNJdY6K-r|PTBka)0(yaH+t6eNt!(cW*4foX|nMb z5_E3FT(BcptOW@^3}L)>UZ(+M-3M%DLqdx1L}>h&2SDo|0Gg|}e$1x*7Xas{jENQ` zSt>jz-=-&LprzsG`=H-ul5<8#x?A+?ln zRjRa&I{NKR+P5ijhh|d+s6XqL!0loOw%amC%w{$u)DeH@J3v(cJzag?`#Q)@xnbdN z>5DJ^s~S}x^p3?A5~-z3u4s>xL0?zFdVZ>1Ab}K?kUE9nR_cJ+Ep}B|0Lk`(C1sHA z52J+b6*1cjZzpo!N9_h6Zy!)9x>R4x4VnhI_N`)i6J)0*Tr_<0#754=dpwut@qAw3 z6}}j}mjPZOeiPBK?4prY%Xt;A#%6yB%+0TX^F7p|mWQE^zlx-N@YiVKZzE}M2VS2x zz#F}$S7WmyfzhpaGEH_o1ygu>bE>O61JiicQ)cM>jjaLhs(IIeY50~6bWf9?a_DrL zpGwb+w)56v{vCA(fDURcrmo?Cf%C%~;S>i@9gsP0UIGOXOa- z=Doc(d*_Ra=8Hz$Sd_Lr{7&dHU=Eug*Z~88AY|~^MeaMH^ROU34{V@=E)YEsHet}m z17u(bhOlrLV}dC>W++f1AR_rEXRGt}HMG#&yN%LSyfWW}&}pFJ*i>k<6gl?6BY#R- zqC;mo1}8Yh8P0LxU*1jg-EVd^+p~@g&{$^$?dg2Geg0oo$T3wFcEB&K6qoMKsoHh& zWA<(><-}T1siAJ_|E)~Z{4+?>N7B3KPdzUyUj9>>KO9pReZ=J|b>;NuyJx#S|K0)N zagRzp4xl=N|KvM0BfQS8k~gdW|KUY09eUp_yGv>zE#1q+Z1(ue|NhmRI)ty7udA&# z{*t13K>xy4aIX*E_wO|v_>w|B`ymxyz=3yykGU55VP~K({t*vs&f&f*fZl@nDm>5p z*{jdP0AVkG>$Ub$0Gyowo&u0(PW4$RSkwi6#A@ILm*`1Zp*5s|pwdUjk&UKmTi%aU7VIoLMgfswYILt+4s(=3;Jf6Q(|0K;V9E~m zVP@QSlG+B=xF-yv``}o7i5#W8GvQ zdslR*Cm&PqWJb}VFnf-fStvY_LhjC_pa$JuX?bc$t|=G8RJOyiUB((hK&O@gwR($+ zCGMP;tq)?KD;*6fas?di%WI+Dk$Q~Mdx%Dka3Rt_9O4kq#dB3jHChCIn0qS7n4GOJywE;QG4(k!3N0@9uoESqzW%V`2K-4w{NGKKGJ1JY+18a zC=pAmV7*D(=vXu>=pxf6*BfH018JpaE=D+iRtk%G9scl;vAcTR%3~UXspfd@DrB=( zRcH+nBVwcimRn2PI)-MgB0PN$>_yBoNkZ*wpVK zr3&K<=3nfB!TKS+V?hac=p$Vy)`w_{&A+!l%e?S;G4n@^aCg+M*AUF#^>N+Kvb0<9 zaqbL5A_g=iXZG!tHHKXCDbL>;l@>Ng0L;GLB#^5+@%Hs?9)2Y9ie4q=s1E!`((Q>; zGzfH$srDIPETU)j9qi{I0O=8dIYg<}-GH2paTUT&WNIYhNUo2(74&@TN)t`&jaFp9 zb38B9XvWX;NaR;r0V^?kM0=ULtsTXHN4juq8ta!>RK zQip`}b^fFB9j{t4Ez0frkkYc1!iEshs(W5qUyOt}$r4)_Gzb_A_l6}c51E0_&SAYGZ#e^cQTKouhj|K2^~J9>sQ zl8NduGAf{E(>BarOSTWtDoHhhU5h@p+*f9v1~#pn0XDFKO)EtXdx<`?1X%^E zH1@(93=z+)PQ@}4UGDsQfS;x7$;&u9!(?7j2j7cSl2z{gwF-(UC)y}HqY?$gdW@d~ z1kjvK+h|tTlO=#bd#MrZT6_m=i4K6k{-B_<_1_f~d*?wO4!o2l53c}v|D2lFH<=Th z5V{pAV=rAcctjpJJS7sl6X1h(ANpTYP#kQt9OF#aD=-1W%>tl(@T+BtQ6M*Q-{a7& z@GxrSR2!@Fz|Y{$3gshF!3^w~e2wl^%)uk$A)J#cbee@ybaHD}cs??<4J>1yDbRCj zPxZWv7!-Fz)SEv!7tTJ{@Ba>`!O?SKBG&NK>gemzi>>nmAB0ZC{56}beUWBh{;Bh7 zb22R=35B+tUMIejPSC!e-7Xx7K8)h0iqW%Fl(7f`=bB(#2CyQGT>QSI8AVNDc1M2Z zN%rh&3%L}!GOAp4X=)I1axpkjC{?H$Vh6}9t=4Q&p@e&+wf;>}yCs?8TjWxyJ5p!Qf

<(a?CQuB=SbU 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 literal 0 HcmV?d00001 diff --git a/docs/fonts/Montserrat/Montserrat-Regular.eot b/docs/fonts/Montserrat/Montserrat-Regular.eot new file mode 100644 index 0000000000000000000000000000000000000000..735d12b51e3e109058fe239ec79c77cbd59f1384 GIT binary patch literal 106287 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

}Sj2B`TwI*d^qb9-QHahAo5Grcy-5U-|39@#! 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

kKuE;l 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

- - - - - - - - - - + @@ -306,23 +335,46 @@ -
- PsychoJS status. -
+
+ +
Source:
+
+ -
Type:
-
    -
  • - -Symbol + + -
  • -
+ + + + + + + + + + + + + + + + + + + + + + + +
@@ -562,107 +614,23 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - -

status

- - - - -
- Properties +
+

PsychoJS status.

+
Type:
+
    +
  • + +Symbol - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Source:
    -
    - - - - - - - -
    +
  • +
@@ -680,16 +648,59 @@ -

(protected) _captureErrors()

- -
- Capture all errors and display them in a pop-up error box. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Capture all errors and display them in a pop-up error box.

@@ -704,50 +715,6 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -768,16 +735,59 @@ -

(async, protected) _configure(configURL, name)

- -
- Configure PsychoJS for the running experiment. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Configure PsychoJS for the running experiment.

@@ -788,6 +798,8 @@ + +
Parameters:
@@ -829,7 +841,7 @@ - the URL of the configuration file +

the URL of the configuration file

@@ -852,7 +864,7 @@ - the name of the experiment +

the name of the experiment

@@ -862,52 +874,6 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -928,18 +894,60 @@ -

(async, protected) _getParticipantIPInfo()

- -
- Get the IP information of the participant, asynchronously. -

Note: we use http://www.geoplugin.net/json.gp.

+
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the IP information of the participant, asynchronously.

+

Note: we use http://www.geoplugin.net/json.gp.

@@ -954,50 +962,6 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1018,16 +982,59 @@ - -

getEnvironment() → {ExperimentHandler.Environment|undefined}

- +

(protected) _makeStatusTopLevel()

-
- Get the experiment's environment. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Make the various Status top level, in order to accommodate PsychoPy's Code Components.

@@ -1041,37 +1048,40 @@ + + + + + + + + + + + + + + + + + + + + + +

getEnvironment() → {ExperimentHandler.Environment|undefined}

+ + + + +
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -1080,12 +1090,54 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Get the experiment's environment.

+
+ + + + + + + + + + + + + + + @@ -1100,12 +1152,12 @@
- the environment of the experiment, or undefined +

the environment of the experiment, or undefined

-
+
Type
@@ -1124,23 +1176,64 @@ - - -

importAttributes(obj)

- -
- Make the attributes of the given object those of window, such that they become global. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Make the attributes of the given object those of window, such that they become global.

@@ -1151,6 +1244,8 @@ + +
Parameters:
@@ -1192,7 +1287,7 @@ - the object whose attributes are to become global +

the object whose attributes are to become global

@@ -1202,52 +1297,6 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1268,17 +1317,59 @@ -

openWindow(options)

- -
- Open a PsychoJS Window. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Open a PsychoJS Window.

This opens a PIXI canvas.

Note: we can only open one window.

@@ -1291,6 +1382,8 @@ + +
Parameters:
@@ -1386,7 +1479,7 @@ - the name of the window +

the name of the window

@@ -1419,7 +1512,7 @@ - whether or not to go fullscreen +

whether or not to go fullscreen

@@ -1432,7 +1525,7 @@ -Color +Color @@ -1452,7 +1545,7 @@ - the background color of the window +

the background color of the window

@@ -1485,7 +1578,7 @@ - the units of the window +

the units of the window

@@ -1518,7 +1611,7 @@ - whether or not to log +

whether or not to log

@@ -1551,8 +1644,8 @@ - whether or not to wait for all rendering operations to be done -before flipping +

whether or not to wait for all rendering operations to be done +before flipping

@@ -1571,50 +1664,6 @@ before flipping -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1629,13 +1678,13 @@ before flipping
-
- exception if a window has already been opened +
+

exception if a window has already been opened

-
+
Type
@@ -1657,25 +1706,65 @@ before flipping - - -

(async) quit(options)

- -
- Close everything and exit nicely at the end of the experiment, -potentially redirecting to one of the URLs previously specified by setRedirectUrls. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Close everything and exit nicely at the end of the experiment, +potentially redirecting to one of the URLs previously specified by setRedirectUrls.

Note: if the resource manager is busy, we inform the participant that he or she needs to wait for a bit.

@@ -1688,6 +1777,8 @@ that he or she needs to wait for a bit.

+ +
Parameters:
@@ -1789,7 +1880,7 @@ that he or she needs to wait for a bit.

- optional message to be displayed in a dialog box before quitting +

optional message to be displayed in a dialog box before quitting

@@ -1823,12 +1914,12 @@ that he or she needs to wait for a bit.

- false + false - whether or not the participant has completed the experiment +

whether the participant has completed the experiment

@@ -1845,52 +1936,6 @@ that he or she needs to wait for a bit.

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1911,16 +1956,59 @@ that he or she needs to wait for a bit.

-

schedule(task, args)

- -
- Schedule a task. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Schedule a task.

@@ -1931,6 +2019,8 @@ that he or she needs to wait for a bit.

+ +
Parameters:
@@ -1961,13 +2051,18 @@ that he or she needs to wait for a bit.

+ +module:util.Scheduler~Task + + + - the task to be scheduled +

the task to be scheduled

@@ -1979,13 +2074,18 @@ that he or she needs to wait for a bit.

+ +* + + + - arguments for that task +

arguments for that task

@@ -1995,52 +2095,6 @@ that he or she needs to wait for a bit.

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2061,16 +2115,59 @@ that he or she needs to wait for a bit.

-

scheduleCondition(condition, thenScheduler, elseScheduler)

- -
- Schedule a series of task based on a condition. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Schedule a series of task based on a condition.

@@ -2081,6 +2178,8 @@ that he or she needs to wait for a bit.

+ +
Parameters:
@@ -2135,7 +2234,7 @@ that he or she needs to wait for a bit.

-Scheduler +Scheduler @@ -2145,7 +2244,7 @@ that he or she needs to wait for a bit.

- scheduler to run if the condition is true +

scheduler to run if the condition is true

@@ -2158,7 +2257,7 @@ that he or she needs to wait for a bit.

-Scheduler +Scheduler @@ -2168,7 +2267,7 @@ that he or she needs to wait for a bit.

- scheduler to run if the condition is false +

scheduler to run if the condition is false

@@ -2178,52 +2277,6 @@ that he or she needs to wait for a bit.

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2244,16 +2297,59 @@ that he or she needs to wait for a bit.

-

setRedirectUrls(completionUrl, cancellationUrl)

- -
- Set the completion and cancellation URL to which the participant will be redirect at the end of the experiment. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the completion and cancellation URL to which the participant will be redirect at the end of the experiment.

@@ -2264,6 +2360,8 @@ that he or she needs to wait for a bit.

+ +
Parameters:
@@ -2305,7 +2403,7 @@ that he or she needs to wait for a bit.

- the completion URL +

the completion URL

@@ -2328,7 +2426,7 @@ that he or she needs to wait for a bit.

- the cancellation URL +

the cancellation URL

@@ -2338,52 +2436,6 @@ that he or she needs to wait for a bit.

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2404,17 +2456,59 @@ that he or she needs to wait for a bit.

-

(async) start(options, resourcesopt)

- -
- Start the experiment. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Start the experiment.

The resources are specified in the following fashion:

-

Note that we only consider the first worksheet for .xls, .xlsx and .odp resource.

- -

'selection' is used to select a subset of condition indices to be used It can be a single integer, an array of indices, or a string to be parsed, e.g.: 5 @@ -1005,6 +1199,8 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: + +

Parameters:
@@ -1040,7 +1236,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: -module:core.ServerManager +module:core.ServerManager @@ -1062,7 +1258,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - the server manager +

the server manager

@@ -1097,7 +1293,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - the name of the resource containing the list of conditions, which must have been registered with the server manager. +

the name of the resource containing the list of conditions, which must have been registered with the server manager.

@@ -1131,12 +1327,12 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - null + null - the selection +

the selection

@@ -1148,50 +1344,6 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1206,13 +1358,13 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.:
-
- Throws an exception if importing the conditions failed. +
+

Throws an exception if importing the conditions failed.

-
+
Type
@@ -1235,12 +1387,12 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.:
- the parsed conditions as an array of 'object as map' +

the parsed conditions as an array of 'object as map'

-
+
Type
@@ -1256,23 +1408,86 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - - - -

(protected) _prepareTrialList() → {void}

- +

(protected) _prepareSequence()

-
- Prepare the trial list. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prepare the sequence of trials.

+

The returned sequence is a matrix (an array of arrays) of trial indices +with nStim columns and nReps rows. Note that this is the transpose of the +matrix return by PsychoPY. +

Example: with 3 trial and 5 repetitions, we get:

+
    +
  • sequential: +[[0 1 2] +[0 1 2] +[0 1 2] +[0 1 2] +[0 1 2]]
  • +
+

These 3*5 = 15 trials will be returned by the TrialHandler generator

+
    +
  • with method = 'sequential' in the order: +0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2
  • +
  • with method = 'random' in the order (amongst others): +2, 1, 0, 0, 2, 1, 0, 1, 2, 0, 1, 2, 1, 2, 0
  • +
  • with method = 'fullRandom' in the order (amongst others): +2, 0, 0, 1, 0, 2, 1, 2, 0, 1, 1, 1, 2, 0, 2
  • +
+

@@ -1286,37 +1501,40 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: + + + + + + + + + + + + + + + + + + + + + +

(protected) _prepareTrialList() → {void}

+ + + + +
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -1325,12 +1543,54 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Prepare the trial list.

+
+ + + + + + + + + + + + + + + @@ -1346,7 +1606,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: -
+
Type
@@ -1362,23 +1622,64 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - - -

addData(key, value)

- -
- Add a key/value pair to data about the current trial held by the experiment handler + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add a key/value pair to data about the current trial held by the experiment handler

@@ -1389,6 +1690,8 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: + +
Parameters:
@@ -1430,7 +1733,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - the key +

the key

@@ -1453,7 +1756,7 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - the value +

the value

@@ -1463,52 +1766,6 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1529,16 +1786,59 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: -

forEach(callback)

- -
- Execute the callback for each trial in the sequence. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Execute the callback for each trial in the sequence.

@@ -1549,6 +1849,8 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: + +
Parameters:
@@ -1595,52 +1897,6 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1661,17 +1917,59 @@ It can be a single integer, an array of indices, or a string to be parsed, e.g.: -

getAttributes() → {Array.string}

- -
- Get the attributes of the trials. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the attributes of the trials.

Note: we assume that all trials in the trialList share the same attributes and consequently consider only the attributes of the first trial.

@@ -1688,48 +1986,6 @@ and consequently consider only the attributes of the first trial.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -1746,12 +2002,12 @@ and consequently consider only the attributes of the first trial.

- the attributes +

the attributes

-
+
Type
@@ -1767,23 +2023,64 @@ and consequently consider only the attributes of the first trial.

- - -

getCurrentTrial() → {Object}

- -
- Get the current trial. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current trial.

@@ -1798,48 +2095,6 @@ and consequently consider only the attributes of the first trial.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -1856,12 +2111,12 @@ and consequently consider only the attributes of the first trial.

- the current trial +

the current trial

-
+
Type
@@ -1877,23 +2132,64 @@ and consequently consider only the attributes of the first trial.

- - -

getEarlierTrial(nopt) → {Object|undefined}

- -
- Get the nth previous trial. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the nth previous trial.

Note: this is useful for comparisons in n-back tasks.

@@ -1905,6 +2201,8 @@ and consequently consider only the attributes of the first trial.

+ +
Parameters:
@@ -1961,12 +2259,12 @@ and consequently consider only the attributes of the first trial.

- -1 + -1 - increment +

increment

@@ -1978,50 +2276,6 @@ and consequently consider only the attributes of the first trial.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2036,12 +2290,12 @@ and consequently consider only the attributes of the first trial.

- the past trial or undefined if attempting to go prior to the first trial. +

the past trial or undefined if attempting to go prior to the first trial.

-
+
Type
@@ -2060,23 +2314,64 @@ and consequently consider only the attributes of the first trial.

- - -

getFutureTrial(nopt) → {Object|undefined}

- -
- Get the nth future or past trial, without advancing through the trial list. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the nth future or past trial, without advancing through the trial list.

@@ -2087,6 +2382,8 @@ and consequently consider only the attributes of the first trial.

+ +
Parameters:
@@ -2143,12 +2440,12 @@ and consequently consider only the attributes of the first trial.

- 1 + 1 - increment +

increment

@@ -2160,50 +2457,6 @@ and consequently consider only the attributes of the first trial.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2218,13 +2471,13 @@ and consequently consider only the attributes of the first trial.

- the future trial (if n is positive) or past trial (if n is negative) -or undefined if attempting to go beyond the last trial. +

the future trial (if n is positive) or past trial (if n is negative) +or undefined if attempting to go beyond the last trial.

-
+
Type
@@ -2243,25 +2496,65 @@ or undefined if attempting to go beyond the last trial. - - -

getSnapshot() → {Snapshot}

- -
- Get a snapshot of the current internal state of the trial handler (e.g. current trial number, -number of trial remaining). +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get a snapshot of the current internal state of the trial handler (e.g. current trial number, +number of trial remaining).

This is typically used in the LoopBegin function, in order to capture the current state of a TrialHandler

@@ -2277,48 +2570,6 @@ number of trial remaining). -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -2335,12 +2586,14 @@ number of trial remaining).
- - a snapshot of the current internal state. +
    +
  • a snapshot of the current internal state.
  • +
-
+
Type
@@ -2356,23 +2609,64 @@ number of trial remaining). - - -

getTrial(index) → {Object|undefined}

- -
- Get the nth trial. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the nth trial.

@@ -2383,6 +2677,8 @@ number of trial remaining). + +
Parameters:
@@ -2427,12 +2723,12 @@ number of trial remaining). - 0 + 0 - the trial index +

the trial index

@@ -2444,50 +2740,6 @@ number of trial remaining). -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2502,12 +2754,12 @@ number of trial remaining).
- the requested trial or undefined if attempting to go beyond the last trial. +

the requested trial or undefined if attempting to go beyond the last trial.

-
+
Type
@@ -2526,23 +2778,64 @@ number of trial remaining). - - -

getTrialIndex() → {number}

- -
- Get the trial index. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the trial index.

@@ -2557,48 +2850,6 @@ number of trial remaining). -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -2615,12 +2866,12 @@ number of trial remaining).
- the current trial index +

the current trial index

-
+
Type
@@ -2636,67 +2887,24 @@ number of trial remaining). - - -

next()

- -
- Helps go through each trial in the sequence one by one, mirrors PsychoPy. -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -2705,11 +2913,51 @@ number of trial remaining). + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

Helps go through each trial in the sequence one by one, mirrors PsychoPy.

+
+ + + + + + + + + + + + @@ -2731,16 +2979,59 @@ number of trial remaining). -

setSeed(seed, log)

- -
- Setter for the seed attribute. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for the seed attribute.

@@ -2751,6 +3042,8 @@ number of trial remaining). + +
Parameters:
@@ -2792,7 +3085,7 @@ number of trial remaining). - the seed value +

the seed value

@@ -2815,7 +3108,7 @@ number of trial remaining). - whether or not to log the change of seed +

whether or not to log the change of seed

@@ -2825,52 +3118,6 @@ number of trial remaining). - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2891,16 +3138,59 @@ number of trial remaining). -

setTrialIndex(index)

- -
- Set the trial index. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the trial index.

@@ -2911,6 +3201,8 @@ number of trial remaining). + +
Parameters:
@@ -2952,7 +3244,7 @@ number of trial remaining). - the new trial index +

the new trial index

@@ -2962,52 +3254,6 @@ number of trial remaining). - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3028,62 +3274,19 @@ number of trial remaining). -

Symbol.iterator()

- -
- Iterator over the trial sequence. - -

This makes it possible to iterate over all trials.

-
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -3092,17 +3295,40 @@ number of trial remaining). + + + + + + + + + + + + + + + + + + + + + + + +
- - - - - +
+

Iterator over the trial sequence.

+

This makes it possible to iterate over all trials.

+
@@ -3119,6 +3345,24 @@ for (const thisTrial of handler) { console.log(thisTrial); } + + + + + + + + + + + + + + + + + + @@ -3132,19 +3376,23 @@ for (const thisTrial of handler) { console.log(thisTrial); } + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-data.html b/docs/module-data.html index 12dd3b3..fe7dae1 100644 --- a/docs/module-data.html +++ b/docs/module-data.html @@ -1,1807 +1,512 @@ + - JSDoc: Module: data - - - + data - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Module: data

+ +
- - +
+ +

data

+ + + + + + + +
+ +
+ + + +
+ +
+ +
+ + + + + +
+ + + + + + + +

Classes

+ +
+
ExperimentHandler
+
+ +
TrialHandler
+
+ +
MultiStairHandler
+
+ +
QuestHandler
+
+ +
Shelf
+
+
+ + + + + + + + + + + + + +

Type Definitions

+ + + +

Snapshot

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
handler + + +TrialHandler + + + +

the trialHandler

name + + +string + + + +

the trialHandler name

nStim + + +number + + + +

the number of stimuli

nTotal + + +number + + + +

the total number of trials that will be run

nRemaining + + +number + + + +

the total number of trial remaining

thisRepN + + +number + + + +

the current repeat

thisTrialN + + +number + + + +

the current trial number within the current repeat

thisN + + +number + + + +

the total number of trials completed so far

thisIndex + + +number + + + +

the index of the current trial in the conditions list

ran + + +number + + + +

whether or not the trial ran

finished + + +number + + + +

whether or not the trials finished

trialAttributes + + +Object + + + +

a list of trial attributes

+ + + + + + + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + + + + + + +
+ +
+ + + + + + +
+
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-hardware.Camera.html b/docs/module-hardware.Camera.html new file mode 100644 index 0000000..df6db87 --- /dev/null +++ b/docs/module-hardware.Camera.html @@ -0,0 +1,2531 @@ + + + + + + Camera - PsychoJS API + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

Camera

+ + + + + + + +
+ +
+ +

+ Camera +

+ + +
+ +
+ +
+ + + + + +

new Camera(options)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
To Do:
+
+
    +
  • add video constraints as parameter
  • +
+
+ +
+ + + + + +
+

This manager handles the recording of video signal.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
win + + +module:core.Window + + + + + + + + + + + +

the associated Window

format + + +string + + + + + + <optional>
+ + + + + +
+ + 'video/webm;codecs=vp9' + +

the video format

clock + + +Clock + + + + + + <optional>
+ + + + + +
+ +

an optional clock

autoLog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to log

+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + +

(protected) _onChange()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Callback for changes to the recording settings.

+

Changes to the settings require the recording to stop and be re-started.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _prepareRecording()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prepare the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

(protected) _upload(tag, waitForCompletionopt, showDialogopt, dialogMsgopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Upload the video recording to the pavlovia server.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
tag + + +string + + + + + + + + + + + +

an optional tag for the video file

waitForCompletion + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to wait for completion +before returning

showDialog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to open a dialog box to inform the participant to wait for the data to be uploaded to the server

dialogMsg + + +string + + + + + + <optional>
+ + + + + +
+ + "" + +

default message informing the participant to wait for the data to be uploaded to the server

+ + + + + + + + + + + + + + + + + + + + + + + + +

authorize(showDialogopt, dialogMsgopt) → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Prompt the user for permission to use the camera on their device.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
showDialog + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether to open a dialog box to inform the +participant to wait for the camera to be initialised

dialogMsg + + +string + + + + + + <optional>
+ + + + + +
+ +

the dialog message

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

whether or not the camera is ready to record

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

close() → {Promise.<void>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Close the camera stream.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the stream has stopped and is now closed

+
+ + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + +

flush() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to flush the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the data has actually been made available

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

getRecording(tag, flushopt)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the current video recording as a VideoClip in the given format.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
tag + + +string + + + + + + + + + + + +

an optional tag for the video clip

flush + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to first flush the recording

+ + + + + + + + + + + + + + + + + + + + + + + + +

getStream() → {MediaStream}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the underlying video stream.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the video stream

+
+ + + +
+
+ Type +
+
+ +MediaStream + + +
+
+ + + + + + + + + + +

getVideo() → {HTMLVideoElement}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get a video element pointing to the Camera stream.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

a video element

+
+ + + +
+
+ Type +
+
+ +HTMLVideoElement + + +
+
+ + + + + + + + + + +

isReady() → {boolean}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Query whether the camera is ready to record.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

true if the camera is ready to record, false otherwise

+
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

open()

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Open the video stream.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

pause() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to pause the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually paused

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

record() → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to start the recording.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually starts

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

resume(options) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to resume the recording.

+

resume has no effect if the recording was not previously paused.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + + +
Properties
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
clear + + +boolean + + + + + + <optional>
+ + + + + +
+ + false + +

whether or not to empty the video buffer before +resuming the recording

+ +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually resumed

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + +

stop(options) → {Promise}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Submit a request to stop the recording.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
options + + +Object + + + +
+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

promise fulfilled when the recording actually stopped, and the recorded +data was made available

+
+ + + +
+
+ Type +
+
+ +Promise + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme. +
+ + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-sound.AudioClip.html b/docs/module-sound.AudioClip.html deleted file mode 100644 index bdad1d1..0000000 --- a/docs/module-sound.AudioClip.html +++ /dev/null @@ -1,1216 +0,0 @@ - - - - - JSDoc: Class: AudioClip - - - - - - - - - - -
- -

Class: AudioClip

- - - - - - -
- -
- -

- sound.AudioClip(options)

- - -
- -
-
- - - - - - -

new AudioClip(options)

- - - - - - -
-

AudioClip encapsulates an audio recording.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
psychoJS - - -module:core.PsychoJS - - - - - - - - - - - - the PsychoJS instance
name - - -String - - - - - - <optional>
- - - - - -
- - 'audioclip' - - the name used when logging messages
format - - -string - - - - - - - - - - - - the format for the audio file
sampleRateHz - - -number - - - - - - - - - - - - the sampling rate
data - - -Blob - - - - - - - - - - - - the audio data, in the given format, at the given sampling rate
autoLog - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to log
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(readonly) Engine :Symbol

- - - - -
- Recognition engines. -
- - - -
Type:
-
    -
  • - -Symbol - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

download()

- - - - - - -
- Offer the audio clip to the participant as a sound file to download. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDuration() → {Promise.<number>}

- - - - - - -
- Get the duration of the audio clip, in seconds. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the duration of the audio clip -
- - - -
-
- Type -
-
- -Promise.<number> - - -
-
- - - - - - - - - - - - - -

setVolume(volume)

- - - - - - -
- Set the volume of the playback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
volume - - -number - - - - the volume of the playback (must be between 0.0 and 1.0)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

startPlayback()

- - - - - - -
- Start playing the audio clip. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

startPlayback(fadeDurationopt)

- - - - - - -
- Stop playing the audio clip. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
fadeDuration - - -number - - - - - - <optional>
- - - - - -
- - 17 - - how long the fading out should last, in ms
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

upload()

- - - - - - -
- Upload the audio clip to the pavlovia server. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.AudioClipPlayer.html b/docs/module-sound.AudioClipPlayer.html deleted file mode 100644 index 94b0141..0000000 --- a/docs/module-sound.AudioClipPlayer.html +++ /dev/null @@ -1,1617 +0,0 @@ - - - - - JSDoc: Class: AudioClipPlayer - - - - - - - - - - -
- -

Class: AudioClipPlayer

- - - - - - -
- -
- -

- sound.AudioClipPlayer(options)

- - -
- -
-
- - - - - - -

new AudioClipPlayer(options)

- - - - - - -
-

This class handles the playback of an audio clip, e.g. a microphone recording.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
psychoJS - - -module:core.PsychoJS - - - - - - - - - - - - the PsychoJS instance
audioClip - - -Object - - - - - - - - - - - - the module:sound.AudioClip
startTime - - -number - - - - - - <optional>
- - - - - -
- - 0 - - start of playback (in seconds)
stopTime - - -number - - - - - - <optional>
- - - - - -
- - -1 - - end of playback (in seconds)
stereo - - -boolean - - - - - - <optional>
- - - - - -
- - true - - whether or not to play the sound or track in stereo
volume - - -number - - - - - - <optional>
- - - - - -
- - 1.0 - - volume of the sound (must be between 0 and 1.0)
loops - - -number - - - - - - <optional>
- - - - - -
- - 0 - - how many times to repeat the track or tone after it has played *
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - -
    -
  • SoundPlayer
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) accept(sound) → {Object|undefined}

- - - - - - -
- Determine whether this player can play the given sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
sound - - -module:sound.Sound - - - - the sound object, which should be an AudioClip
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- an instance of AudioClipPlayer if sound is an AudioClip or undefined otherwise -
- - - -
-
- Type -
-
- -Object -| - -undefined - - -
-
- - - - - - - - - - - - - -

getDuration() → {number}

- - - - - - -
- Get the duration of the AudioClip, in seconds. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the duration of the clip, in seconds -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

play(loops, fadeDurationopt)

- - - - - - -
- Start playing the sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
loops - - -number - - - - - - - - - - - - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.
fadeDuration - - -number - - - - - - <optional>
- - - - - -
- - 17 - - how long should the fading in last in ms
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDuration(duration_s)

- - - - - - -
- Set the duration of the audio clip. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
duration_s - - -number - - - - the duration of the clip in seconds
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLoops(loops)

- - - - - - -
- Set the number of loops. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
loops - - -number - - - - how many times to repeat the clip after it has played once. If loops == -1, the clip will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVolume(volume, muteopt)

- - - - - - -
- Set the volume of the playback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
volume - - -number - - - - - - - - - - - - the volume of the playback (must be between 0.0 and 1.0)
mute - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to mute the playback
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

stop(fadeDurationopt)

- - - - - - -
- Stop playing the sound immediately. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
fadeDuration - - -number - - - - - - <optional>
- - - - - -
- - 17 - - how long the fading out should last, in ms
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.Microphone.html b/docs/module-sound.Microphone.html deleted file mode 100644 index 4583f1d..0000000 --- a/docs/module-sound.Microphone.html +++ /dev/null @@ -1,1441 +0,0 @@ - - - - - JSDoc: Class: Microphone - - - - - - - - - - -
- -

Class: Microphone

- - - - - - -
- -
- -

- sound.Microphone(options, @param)

- - -
- -
-
- - - - - - -

new Microphone(options, @param)

- - - - - - -
-

This manager handles the recording of audio signal.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
options - - -Object - - - - - - - - - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
psychoJS - - -module:core.PsychoJS - - - - the PsychoJS instance
- -
@param - - -module:core.Window - - - - - - - - - - - - options.win - the associated Window
options.format - - -string - - - - - - <optional>
- - - - - -
- - 'audio/webm;codecs=opus' - - the format for the audio file
options.sampleRateHz - - -number - - - - - - <optional>
- - - - - -
- - 48000 - - the audio sampling rate, in Hz
options.clock - - -Clock - - - - - - <optional>
- - - - - -
- - an optional clock
options.autoLog - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to log
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

flush

- - - - -
- Submit a request to flush the recording. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

pause

- - - - -
- Submit a request to pause the recording. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

resume

- - - - -
- Submit a request to resume the recording. - -

resume has no effect if the recording was not previously paused.

-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

start

- - - - -
- Submit a request to start the recording. - -

Note that it typically takes 50ms-200ms for the recording to actually starts once -a request to start has been submitted.

-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

stop

- - - - -
- Submit a request to stop the recording. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

(protected) _onChange()

- - - - - - -
- Callback for changes to the recording settings. - -

Changes to the settings require the recording to stop and be re-started.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(protected) _prepareRecording()

- - - - - - -
- Prepare the recording. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

download(filename)

- - - - - - -
- Offer the audio recording to the participant as a sound file to download. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
filename - - -string - - - - the filename
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRecording(tag, flushopt)

- - - - - - -
- Get the current audio recording as an AudioClip in the given format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
tag - - -string - - - - - - - - - - - - an optional tag for the audio clip
flush - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to first flush the recording
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

upload(tag)

- - - - - - -
- Upload the audio recording to the pavlovia server. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - an optional tag for the audio file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.Sound.html b/docs/module-sound.Sound.html index 645734a..7d14cba 100644 --- a/docs/module-sound.Sound.html +++ b/docs/module-sound.Sound.html @@ -1,23 +1,47 @@ + - JSDoc: Class: Sound - - - + Sound - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Class: Sound

+ + + + +
+ +

Sound

+ @@ -28,16 +52,17 @@
-

- sound.Sound(options)

+

+ sound. -

This class handles sound playing (tones and tracks)

- + Sound +

+ +

This class handles sound playing (tones and tracks)

  • If value is a number then a tone will be generated at that frequency in Hz.
  • It value is a string, it must either be a note in the PsychoPy format (e.g 'A', 'Bfl', 'B', 'C', 'Csh'), in which case an octave must also be given, or the name of the resource track.
-

Note: the PsychoPy hamming parameter has not been implemented yet. It might be rather tricky to do so using Tone.js

@@ -45,23 +70,61 @@ Tone.js

-
+
+

Constructor

-

new Sound(options)

- +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -69,6 +132,26 @@ Tone.js

+ + + + + + +
Example
+ +
[...]
+const track = new Sound({
+  win: psychoJS.window,
+  value: 440,
+  secs: 0.5
+});
+track.setVolume(1.0);
+track.play(2);
+ + + +
Parameters:
@@ -168,7 +251,7 @@ Tone.js

- the name used when logging messages from this stimulus +

the name used when logging messages from this stimulus

@@ -203,7 +286,7 @@ Tone.js

- the associated Window +

the associated Window

@@ -240,12 +323,12 @@ Tone.js

- 'C' + 'C' - the sound value (see above for a full description) +

the sound value (see above for a full description)

@@ -279,12 +362,12 @@ Tone.js

- 4 + 4 - the octave corresponding to the tone (if applicable) +

the octave corresponding to the tone (if applicable)

@@ -318,12 +401,12 @@ Tone.js

- 0.5 + 0.5 - duration of the tone (in seconds) If secs == -1, the sound will play indefinitely. +

duration of the tone (in seconds) If secs == -1, the sound will play indefinitely.

@@ -357,12 +440,12 @@ Tone.js

- 0 + 0 - start of playback for tracks (in seconds) +

start of playback for tracks (in seconds)

@@ -396,12 +479,12 @@ Tone.js

- -1 + -1 - end of playback for tracks (in seconds) +

end of playback for tracks (in seconds)

@@ -435,12 +518,12 @@ Tone.js

- true + true - whether or not to play the sound or track in stereo +

whether or not to play the sound or track in stereo

@@ -474,12 +557,12 @@ Tone.js

- 1.0 + 1.0 - volume of the sound (must be between 0 and 1.0) +

volume of the sound (must be between 0 and 1.0)

@@ -513,12 +596,12 @@ Tone.js

- 0 + 0 - how many times to repeat the track or tone after it has played once. If loops == -1, the track or tone will repeat indefinitely until stopped. +

how many times to repeat the track or tone after it has played once. If loops == -1, the track or tone will repeat indefinitely until stopped.

@@ -552,12 +635,12 @@ Tone.js

- true + true - whether or not to log +

whether or not to log

@@ -576,81 +659,24 @@ Tone.js

-
+ + + + + + + + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
[...]
-const track = new Sound({
-  win: psychoJS.window,
-  value: 440,
-  secs: 0.5
-});
-track.setVolume(1.0);
-track.play(2);
- - - - -
- -

Extends

@@ -666,10 +692,10 @@ track.play(2);
- + - + @@ -683,16 +709,59 @@ track.play(2); - -

(protected) _getPlayer() → {SoundPlayer}

- +

(protected) _getPlayer() → {SoundPlayer}

-
- Identify the appropriate player for the sound. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Identify the appropriate player for the sound.

@@ -707,48 +776,6 @@ track.play(2); -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -765,13 +792,13 @@ track.play(2);
-
- exception if no appropriate SoundPlayer could be found for the sound +
+

exception if no appropriate SoundPlayer could be found for the sound

-
+
Type
@@ -794,18 +821,18 @@ track.play(2);
- the appropriate SoundPlayer +

the appropriate SoundPlayer

-
+
Type
-SoundPlayer +SoundPlayer
@@ -815,23 +842,64 @@ track.play(2); - - -

getDuration() → {number}

- -
- Get the duration of the sound, in seconds. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the duration of the sound, in seconds.

@@ -846,48 +914,6 @@ track.play(2); -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -904,12 +930,12 @@ track.play(2);
- the duration of the sound, in seconds +

the duration of the sound, in seconds

-
+
Type
@@ -925,171 +951,21 @@ track.play(2); - - -

play(loops, logopt)

- -
- Start playing the sound. - -

Note: Sounds are played independently from the stimuli of the experiments, i.e. the experiment will not stop until the sound is finished playing. -Repeat calls to play may results in the sounds being played on top of each other.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
loops - - -number - - - - - - - - - - - - how many times to repeat the sound after it plays once. If loops == -1, the sound will repeat indefinitely until stopped.
log - - -boolean - - - - - - <optional>
- - - - - -
- - true - - whether or not to log
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
  • sound/Sound.js, line 102 @@ -1101,11 +977,157 @@ Repeat calls to play may results in the sounds being played on top of each other + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

Start playing the sound.

+

Note: Sounds are played independently from the stimuli of the experiments, i.e. the experiment will not stop until the sound is finished playing. +Repeat calls to play may results in the sounds being played on top of each other.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
loops + + +number + + + + + + + + + + + +

how many times to repeat the sound after it plays once. If loops == -1, the sound will repeat indefinitely until stopped.

log + + +boolean + + + + + + <optional>
+ + + + + +
+ + true + +

whether or not to log

+ + + @@ -1127,16 +1149,59 @@ Repeat calls to play may results in the sounds being played on top of each other -

setLoops(loopsopt, logopt)

- -
- Set the number of loops. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the number of loops.

@@ -1147,6 +1212,8 @@ Repeat calls to play may results in the sounds being played on top of each other + +
Parameters:
@@ -1203,12 +1270,12 @@ Repeat calls to play may results in the sounds being played on top of each other - 0 + 0 - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped. +

how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.

@@ -1242,12 +1309,12 @@ Repeat calls to play may results in the sounds being played on top of each other - true + true - whether of not to log +

whether of not to log

@@ -1257,52 +1324,6 @@ Repeat calls to play may results in the sounds being played on top of each other - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1323,16 +1344,59 @@ Repeat calls to play may results in the sounds being played on top of each other -

setSecs(secsopt, logopt)

- -
- Set the duration (in seconds) + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the duration (in seconds)

@@ -1343,6 +1407,8 @@ Repeat calls to play may results in the sounds being played on top of each other + +
Parameters:
@@ -1399,12 +1465,12 @@ Repeat calls to play may results in the sounds being played on top of each other - 0.5 + 0.5 - duration of the tone (in seconds) If secs == -1, the sound will play indefinitely. +

duration of the tone (in seconds) If secs == -1, the sound will play indefinitely.

@@ -1438,12 +1504,12 @@ Repeat calls to play may results in the sounds being played on top of each other - true + true - whether or not to log +

whether or not to log

@@ -1453,52 +1519,6 @@ Repeat calls to play may results in the sounds being played on top of each other - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1519,16 +1539,59 @@ Repeat calls to play may results in the sounds being played on top of each other -

setSound(sound, logopt)

- -
- Set the sound value on demand past initialisation. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the sound value on demand past initialisation.

@@ -1539,6 +1602,8 @@ Repeat calls to play may results in the sounds being played on top of each other + +
Parameters:
@@ -1596,7 +1661,7 @@ Repeat calls to play may results in the sounds being played on top of each other - a sound instance to replace the current one +

a sound instance to replace the current one

@@ -1630,12 +1695,12 @@ Repeat calls to play may results in the sounds being played on top of each other - true + true - whether or not to log +

whether or not to log

@@ -1645,52 +1710,6 @@ Repeat calls to play may results in the sounds being played on top of each other - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1711,16 +1730,59 @@ Repeat calls to play may results in the sounds being played on top of each other -

setVolume(volume, muteopt, logopt)

- -
- Set the playing volume of the sound. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the playing volume of the sound.

@@ -1731,6 +1793,8 @@ Repeat calls to play may results in the sounds being played on top of each other + +
Parameters:
@@ -1788,7 +1852,7 @@ Repeat calls to play may results in the sounds being played on top of each other - the volume (values should be between 0 and 1) +

the volume (values should be between 0 and 1)

@@ -1822,12 +1886,12 @@ Repeat calls to play may results in the sounds being played on top of each other - false + false - whether or not to mute the sound +

whether or not to mute the sound

@@ -1861,12 +1925,12 @@ Repeat calls to play may results in the sounds being played on top of each other - true + true - whether of not to log +

whether of not to log

@@ -1876,52 +1940,6 @@ Repeat calls to play may results in the sounds being played on top of each other - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1942,16 +1960,59 @@ Repeat calls to play may results in the sounds being played on top of each other -

stop(options)

- -
- Stop playing the sound immediately. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Stop playing the sound immediately.

@@ -1962,6 +2023,8 @@ Repeat calls to play may results in the sounds being played on top of each other + +
Parameters:
@@ -2060,12 +2123,12 @@ Repeat calls to play may results in the sounds being played on top of each other - true + true - whether or not to log +

whether or not to log

@@ -2084,52 +2147,6 @@ Repeat calls to play may results in the sounds being played on top of each other -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - @@ -2156,19 +2173,23 @@ Repeat calls to play may results in the sounds being played on top of each other + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-sound.SoundPlayer.html b/docs/module-sound.SoundPlayer.html deleted file mode 100644 index 0ec7a7d..0000000 --- a/docs/module-sound.SoundPlayer.html +++ /dev/null @@ -1,1048 +0,0 @@ - - - - - JSDoc: Interface: SoundPlayer - - - - - - - - - - -
- -

Interface: SoundPlayer

- - - - - - -
- -
- -

- sound.SoundPlayer

- - -
- -
-
- - -

SoundPlayer is an interface for the sound players, who are responsible for actually playing the sounds, i.e. the tracks or the tones.

- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - -

Extends

- - - - -
    -
  • PsychObject
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(abstract, static) accept() → {Object|undefined}

- - - - - - -
- Determine whether this player can play the given sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDescription
- - -module:sound.Sound - - - - the sound
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- an instance of the SoundPlayer that can play the sound, or undefined if none could be found -
- - - -
-
- Type -
-
- -Object -| - -undefined - - -
-
- - - - - - - - - - - - - -

(abstract) getDuration()

- - - - - - -
- Get the duration of the sound, in seconds. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(abstract) play(loopsopt)

- - - - - - -
- Start playing the sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
loops - - -number - - - - - - <optional>
- - - - - -
how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(abstract) setDuration()

- - - - - - -
- Set the duration of the sound, in seconds. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(abstract) setLoops(loops)

- - - - - - -
- Set the number of loops. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
loops - - -number - - - - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(abstract) setVolume(volume, muteopt)

- - - - - - -
- Set the volume of the tone. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
volume - - -Integer - - - - - - - - - - - - the volume of the tone
mute - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to mute the tone
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(abstract) stop()

- - - - - - -
- Stop playing the sound immediately. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.TonePlayer.html b/docs/module-sound.TonePlayer.html deleted file mode 100644 index dd9a0fb..0000000 --- a/docs/module-sound.TonePlayer.html +++ /dev/null @@ -1,1528 +0,0 @@ - - - - - JSDoc: Class: TonePlayer - - - - - - - - - - -
- -

Class: TonePlayer

- - - - - - -
- -
- -

- sound.TonePlayer(options)

- - -
- -
-
- - - - - - -

new TonePlayer(options)

- - - - - - -
-

This class handles the playing of tones.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
psychoJS - - -module:core.PsychoJS - - - - - - - - - - - - the PsychoJS instance
duration_s - - -number - - - - - - <optional>
- - - - - -
- - 0.5 - - duration of the tone (in seconds). If duration_s == -1, the sound will play indefinitely.
note - - -string -| - -number - - - - - - <optional>
- - - - - -
- - 'C4' - - note (if string) or frequency (if number)
volume - - -number - - - - - - <optional>
- - - - - -
- - 1.0 - - volume of the tone (must be between 0 and 1.0)
loops - - -number - - - - - - <optional>
- - - - - -
- - 0 - - how many times to repeat the tone after it has played once. If loops == -1, the tone will repeat indefinitely until stopped.
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - -
    -
  • SoundPlayer
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(protected, static) _initSoundLibrary()

- - - - - - -
- Initialise the sound library. - -

Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, -we throw an exception.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) accept(sound) → {Object|undefined}

- - - - - - -
- Determine whether this player can play the given sound. - -

Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, -we throw an exception.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
sound - - -module:sound.Sound - - - - the sound
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- an instance of TonePlayer that can play the given sound or undefined otherwise -
- - - -
-
- Type -
-
- -Object -| - -undefined - - -
-
- - - - - - - - - - - - - -

getDuration() → {number}

- - - - - - -
- Get the duration of the sound. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the duration of the sound, in seconds -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

play(loopsopt)

- - - - - - -
- Start playing the sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
loops - - -boolean - - - - - - <optional>
- - - - - -
how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDuration(duration_s)

- - - - - - -
- Set the duration of the tone. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
duration_s - - -number - - - - the duration of the tone (in seconds) If duration_s == -1, the sound will play indefinitely.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLoops(loops)

- - - - - - -
- Set the number of loops. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
loops - - -number - - - - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVolume(volume, muteopt)

- - - - - - -
- Set the volume of the tone. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
volume - - -Integer - - - - - - - - - - - - the volume of the tone
mute - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to mute the tone
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

stop()

- - - - - - -
- Stop playing the sound immediately. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.TrackPlayer.html b/docs/module-sound.TrackPlayer.html deleted file mode 100644 index ae2bcd6..0000000 --- a/docs/module-sound.TrackPlayer.html +++ /dev/null @@ -1,1627 +0,0 @@ - - - - - JSDoc: Class: TrackPlayer - - - - - - - - - - -
- -

Class: TrackPlayer

- - - - - - -
- -
- -

- sound.TrackPlayer(options)

- - -
- -
-
- - - - - - -

new TrackPlayer(options)

- - - - - - -
-

This class handles the playback of sound tracks.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
psychoJS - - -module:core.PsychoJS - - - - - - - - - - - - the PsychoJS instance
howl - - -Object - - - - - - - - - - - - the sound object (see https://howlerjs.com/)
startTime - - -number - - - - - - <optional>
- - - - - -
- - 0 - - start of playback (in seconds)
stopTime - - -number - - - - - - <optional>
- - - - - -
- - -1 - - end of playback (in seconds)
stereo - - -boolean - - - - - - <optional>
- - - - - -
- - true - - whether or not to play the sound or track in stereo
volume - - -number - - - - - - <optional>
- - - - - -
- - 1.0 - - volume of the sound (must be between 0 and 1.0)
loops - - -number - - - - - - <optional>
- - - - - -
- - 0 - - how many times to repeat the track or tone after it has played *
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
To Do:
-
-
    -
  • stopTime is currently not implemented (tracks will play from startTime to finish)
  • - -
  • stereo is currently not implemented
  • -
-
- -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - -
    -
  • SoundPlayer
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) accept(sound) → {Object|undefined}

- - - - - - -
- Determine whether this player can play the given sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
sound - - -module:sound.Sound - - - - the sound, which should be the name of an audio resource - file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- an instance of TrackPlayer that can play the given track or undefined otherwise -
- - - -
-
- Type -
-
- -Object -| - -undefined - - -
-
- - - - - - - - - - - - - -

getDuration() → {number}

- - - - - - -
- Get the duration of the sound, in seconds. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the duration of the track, in seconds -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

play(loops, fadeDurationopt)

- - - - - - -
- Start playing the sound. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
loops - - -number - - - - - - - - - - - - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.
fadeDuration - - -number - - - - - - <optional>
- - - - - -
- - 17 - - how long should the fading in last in ms
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDuration(duration_s)

- - - - - - -
- Set the duration of the track. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
duration_s - - -number - - - - the duration of the track in seconds
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLoops(loops)

- - - - - - -
- Set the number of loops. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
loops - - -number - - - - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVolume(volume, muteopt)

- - - - - - -
- Set the volume of the tone. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
volume - - -Integer - - - - - - - - - - - - the volume of the track (must be between 0 and 1.0)
mute - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to mute the track
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

stop(fadeDurationopt)

- - - - - - -
- Stop playing the sound immediately. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
fadeDuration - - -number - - - - - - <optional>
- - - - - -
- - 17 - - how long should the fading out last in ms
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.Transcriber.html b/docs/module-sound.Transcriber.html deleted file mode 100644 index 8fd7016..0000000 --- a/docs/module-sound.Transcriber.html +++ /dev/null @@ -1,1395 +0,0 @@ - - - - - JSDoc: Class: Transcriber - - - - - - - - - - -
- -

Class: Transcriber

- - - - - - -
- -
- -

- sound.Transcriber(options)

- - -
- -
-
- - - - - - -

new Transcriber(options)

- - - - - - -
-

This manager handles the transcription of speech into text.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
psychoJS - - -module:core.PsychoJS - - - - - - - - - - - - the PsychoJS instance
name - - -String - - - - - - - - - - - - the name used when logging messages
bufferSize - - -number - - - - - - <optional>
- - - - - -
- - 10000 - - the maximum size of the circular transcript buffer
continuous - - -Array.<String> - - - - - - <optional>
- - - - - -
- - true - - whether or not to continuously recognise
lang - - -Array.<String> - - - - - - <optional>
- - - - - -
- - 'en-US' - - the spoken language
interimResults - - -Array.<String> - - - - - - <optional>
- - - - - -
- - false - - whether or not to make interim results available
maxAlternatives - - -Array.<String> - - - - - - <optional>
- - - - - -
- - 1 - - the maximum number of recognition alternatives
tokens - - -Array.<String> - - - - - - <optional>
- - - - - -
- - [] - - the tokens to be recognised. This is experimental technology, not available in all browser.
clock - - -Clock - - - - - - <optional>
- - - - - -
- - an optional clock
autoLog - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to log
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
To Do:
-
-
    -
  • deal with alternatives, interim results, and recognition errors
  • -
-
- -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(protected) _onChange()

- - - - - - -
- Callback for changes to the recognition settings. - -

Changes to the recognition settings require the recognition to stop and be re-started.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(protected) _prepareTranscription()

- - - - - - -
- Prepare the transcription. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

clearTranscripts()

- - - - - - -
- Clear all transcripts and resets the circular buffers. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTranscripts(options) → {Array.<Transcript>}

- - - - - - -
- Get the list of transcripts still in the buffer, i.e. those that have not been -previously cleared by calls to getTranscripts with clear = true. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
options - - -Object - - - - -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
transcriptList - - -Array.<string> - - - - - - <optional>
- - - - - -
- - [] - - the list of transcripts texts to consider. If transcriptList is empty, we consider all transcripts.
clear - - -boolean - - - - - - <optional>
- - - - - -
- - false - - whether or not to keep in the buffer the transcripts for a subsequent call to getTranscripts. If a keyList has been given and clear = true, we only remove from the buffer those keys in keyList
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the list of transcripts still in the buffer -
- - - -
-
- Type -
-
- -Array.<Transcript> - - -
-
- - - - - - - - - - - - - -

start() → {Promise}

- - - - - - -
- Start the transcription. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- promise fulfilled when the transcription actually started -
- - - -
-
- Type -
-
- -Promise - - -
-
- - - - - - - - - - - - - -

stop() → {Promise}

- - - - - - -
- Stop the transcription. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- promise fulfilled when the speech recognition actually stopped -
- - - -
-
- Type -
-
- -Promise - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.Transcript.html b/docs/module-sound.Transcript.html deleted file mode 100644 index 84cefc5..0000000 --- a/docs/module-sound.Transcript.html +++ /dev/null @@ -1,171 +0,0 @@ - - - - - JSDoc: Class: Transcript - - - - - - - - - - -
- -

Class: Transcript

- - - - - - -
- -
- -

- sound.Transcript()

- - -
- -
-
- - - - - - -

new Transcript()

- - - - - - -
- Transcript returned by the transcriber -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-sound.html b/docs/module-sound.html index 74b5e20..458c490 100644 --- a/docs/module-sound.html +++ b/docs/module-sound.html @@ -1,23 +1,47 @@ + - JSDoc: Module: sound - - - + sound - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Module: sound

+ + + + +
+ +

sound

+ @@ -33,13 +57,15 @@
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-util.Clock.html b/docs/module-util.Clock.html deleted file mode 100644 index a16d5dd..0000000 --- a/docs/module-util.Clock.html +++ /dev/null @@ -1,495 +0,0 @@ - - - - - JSDoc: Class: Clock - - - - - - - - - - -
- -

Class: Clock

- - - - - - -
- -
- -

- util.Clock()

- - -
- -
-
- - - - - - -

new Clock()

- - - - - - -
-

Clock is a MonotonicClock that also offers the possibility of being reset.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - -
    -
  • MonotonicClock
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

add(deltaTimeopt)

- - - - - - -
- Add more time to the clock's 'start' time (t0). - -

Note: by adding time to t0, the current time is pushed forward (it becomes -smaller). As a consequence, getTime() may return a negative number.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
deltaTime - - -number - - - - - - <optional>
- - - - - -
the time to be added to the clock's start time (t0)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

reset(newTimeopt)

- - - - - - -
- Reset the time on the clock. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
newTime - - -number - - - - - - <optional>
- - - - - -
- - 0 - - the new time on the clock.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.Color.html b/docs/module-util.Color.html deleted file mode 100644 index b236c55..0000000 --- a/docs/module-util.Color.html +++ /dev/null @@ -1,2076 +0,0 @@ - - - - - JSDoc: Class: Color - - - - - - - - - - -
- -

Class: Color

- - - - - - -
- -
- -

- util.Color(objopt, colorspaceopt)

- - -
- -
-
- - - - - - -

new Color(objopt, colorspaceopt)

- - - - - - -
-

This class handles multiple color spaces, and offers various -static methods for converting colors from one space to another.

- -

The constructor accepts the following color representations: -

    -
  • a named color, e.g. 'aliceblue' (the colorspace must be RGB)
  • -
  • an hexadecimal string representation, e.g. '#FF0000' (the colorspace must be RGB)
  • -
  • an hexadecimal number representation, e.g. 0xFF0000 (the colorspace must be RGB)
  • -
  • a triplet of numbers, e.g. [-1, 0, 1], [0, 128, 255] (the numbers must be within the range determined by the colorspace)
  • -
-

- -

Note: internally, colors are represented as a [r,g,b] triplet with r,g,b in [0,1].

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
obj - - -string -| - -number -| - -Array.<number> -| - -undefined - - - - - - <optional>
- - - - - -
- - 'black' - - an object representing a color
colorspace - - -module:util.Color#COLOR_SPACE -| - -undefined - - - - - - <optional>
- - - - - -
- - Color.COLOR_SPACE.RGB - - the colorspace of that color
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
To Do:
-
-
    -
  • implement HSV, DKL, and LMS colorspaces
  • -
-
- -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(readonly) COLOR_SPACE :Symbol

- - - - -
- Color spaces. -
- - - -
Type:
-
    -
  • - -Symbol - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(readonly) NAMED_COLORS :string

- - - - -
- Named colors. -
- - - -
Type:
-
    -
  • - -string - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

(static) hex() → {string}

- - - - - - -
- Get the hexadecimal color code equivalent of this Color. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hexadecimal color code equivalent -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) hexToRgb(hex) → {Array.<number>}

- - - - - - -
- Get the [0,1] RGB triplet equivalent of the hexadecimal color code. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hex - - -string - - - - the hexadecimal color code
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the [0,1] RGB triplet equivalent -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - - - - - - - - -

(static) hexToRgb255(hex) → {Array.<number>}

- - - - - - -
- Get the [0,255] RGB triplet equivalent of the hexadecimal color code. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hex - - -string - - - - the hexadecimal color code
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the [0,255] RGB triplet equivalent -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - - - - - - - - -

(static) int() → {number}

- - - - - - -
- Get the integer code equivalent of this Color. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integer code equivalent -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

(static) rgb() → {Array.<number>}

- - - - - - -
- Get the [0,1] RGB triplet equivalent of this Color. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the [0,1] RGB triplet equivalent -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - - - - - - - - -

(static) rgb255() → {Array.<number>}

- - - - - - -
- Get the [0,255] RGB triplet equivalent of this Color. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the [0,255] RGB triplet equivalent -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - - - - - - - - -

(static) rgb255ToHex(rgb255) → {string}

- - - - - - -
- Get the hexadecimal color code equivalent of the [0, 255] RGB triplet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
rgb255 - - -Array.<number> - - - - the [0, 255] RGB triplet
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hexadecimal color code equivalent -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) rgb255ToInt(rgb255) → {number}

- - - - - - -
- Get the integer equivalent of the [0, 255] RGB triplet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
rgb255 - - -Array.<number> - - - - the [0, 255] RGB triplet
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integer equivalent -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

(static) rgbFull() → {Array.<number>}

- - - - - - -
- Get the [-1,1] RGB triplet equivalent of this Color. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the [-1,1] RGB triplet equivalent -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - - - - - - - - -

(static) rgbToHex(rgb) → {string}

- - - - - - -
- Get the hexadecimal color code equivalent of the [0, 1] RGB triplet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
rgb - - -Array.<number> - - - - the [0, 1] RGB triplet
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hexadecimal color code equivalent -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) rgbToInt(rgb) → {number}

- - - - - - -
- Get the integer equivalent of the [0, 1] RGB triplet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
rgb - - -Array.<number> - - - - the [0, 1] RGB triplet
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integer equivalent -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

(static) toString() → {string}

- - - - - - -
- String representation of the color, i.e. the hexadecimal representation. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the representation. -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.ColorMixin.html b/docs/module-util.ColorMixin.html index 92e5ff9..0c9fd81 100644 --- a/docs/module-util.ColorMixin.html +++ b/docs/module-util.ColorMixin.html @@ -1,23 +1,47 @@ + - JSDoc: Mixin: ColorMixin - - - + ColorMixin - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Mixin: ColorMixin

+ + + + +
+ +

ColorMixin

+ @@ -29,48 +53,23 @@

- util.ColorMixin

+ util. + + ColorMixin +
-
+
-

This mixin implement color and contrast changes for visual stimuli

- - - - +
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
+ + + +

This mixin implement color and contrast changes for visual stimuli

+ + + - -
- +
@@ -96,8 +124,10 @@ - + + + @@ -111,16 +141,59 @@ -

getContrastedColor(color, contrast)

- -
- Get a new contrasted Color. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get a new contrasted Color.

@@ -131,6 +204,8 @@ + +
Parameters:
@@ -178,7 +253,7 @@ - the color +

the color

@@ -201,7 +276,7 @@ - the contrast (must be between 0 and 1) +

the contrast (must be between 0 and 1)

@@ -211,52 +286,6 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -277,16 +306,59 @@ -

setColor(color, logopt)

- -
- Setter for Color attribute. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for Color attribute.

@@ -297,6 +369,8 @@ + +
Parameters:
@@ -332,7 +406,7 @@ -Color +Color @@ -354,7 +428,7 @@ - the new color +

the new color

@@ -388,12 +462,12 @@ - false + false - whether or not to log +

whether or not to log

@@ -403,52 +477,6 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -469,16 +497,59 @@ -

setContrast(contrast, logopt)

- -
- Setter for Contrast attribute. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Setter for Contrast attribute.

@@ -489,6 +560,8 @@ + +
Parameters:
@@ -546,7 +619,7 @@ - the new contrast (must be between 0 and 1) +

the new contrast (must be between 0 and 1)

@@ -580,12 +653,12 @@ - false + false - whether or not to log +

whether or not to log

@@ -597,52 +670,6 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - @@ -669,19 +696,23 @@ + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-util.CountdownTimer.html b/docs/module-util.CountdownTimer.html deleted file mode 100644 index fe9a647..0000000 --- a/docs/module-util.CountdownTimer.html +++ /dev/null @@ -1,667 +0,0 @@ - - - - - JSDoc: Class: CountdownTimer - - - - - - - - - - -
- -

Class: CountdownTimer

- - - - - - -
- -
- -

- util.CountdownTimer(startTimeopt)

- - -
- -
-
- - - - - - -

new CountdownTimer(startTimeopt)

- - - - - - -
-

CountdownTimer is a clock counts down from the time of last reset. - - - - - - - - - -

Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
startTime - - -number - - - - - - <optional>
- - - - - -
- - 0 - - the start time of the countdown
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - -
    -
  • Clock
  • -
- - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

add(deltaTimeopt)

- - - - - - -
- Add more time to the clock's 'start' time (t0). - -

Note: by adding time to t0, you push the current time forward (make it -smaller). As a consequence, getTime() may return a negative number.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
deltaTime - - -number - - - - - - <optional>
- - - - - -
the time to be added to the clock's start time (t0)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTime() → {number}

- - - - - - -
- Get the time currently left on the countdown. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the time left on the countdown (in seconds) -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

reset(newTimeopt)

- - - - - - -
- Reset the time on the countdown. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
newTime - - -number - - - - - - <optional>
- - - - - -
if newTime is undefined, the countdown time is reset to zero, otherwise we set it -to newTime
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.EventEmitter.html b/docs/module-util.EventEmitter.html deleted file mode 100644 index ce308ab..0000000 --- a/docs/module-util.EventEmitter.html +++ /dev/null @@ -1,1009 +0,0 @@ - - - - - JSDoc: Class: EventEmitter - - - - - - - - - - -
- -

Class: EventEmitter

- - - - - - -
- -
- -

- util.EventEmitter()

- - -
- -
-
- - - - - - -

new EventEmitter()

- - - - - - -
-

EventEmitter implements the classic observer/observable pattern.

- -

Note: this is heavily inspired by http://www.datchley.name/es6-eventemitter/

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
let observable = new EventEmitter();
-let uuid1 = observable.on('change', data => { console.log(data); });
-observable.emit("change", { a: 1 });
-observable.off("change", uuid1);
-observable.emit("change", { a: 1 });
- - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

emit(name, data) → {boolean}

- - - - - - -
- Emit an event with a given name and associated data. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -String - - - - the name of the event
data - - -object - - - - the data of the event
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if at least one listener has been registered for that event, and false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

off(name, listener)

- - - - - - -
- Remove the listener with the given uuid associated to the given event name. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -String - - - - the name of the event
listener - - -module:util.EventEmitter~Listener - - - - a listener called upon emission of the event
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

on(name, listener)

- - - - - - -
- Register a new listener for events with the given name emitted by this instance. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -String - - - - the name of the event
listener - - -module:util.EventEmitter~Listener - - - - a listener called upon emission of the event
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- string - the unique identifier associated with that (event, listener) pair (useful to remove the listener) -
- - - - - - - - - - - - - - - -

once(name, listener)

- - - - - - -
- Register a new listener for the given event name, and remove it as soon as the event has been emitted. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -String - - - - the name of the event
listener - - -module:util.EventEmitter~Listener - - - - a listener called upon emission of the event
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- string - the unique identifier associated with that (event, listener) pair (useful to remove the listener) -
- - - - - - - - - - - - - -

Type Definitions

- - - - - - - -

Listener(data)

- - - - - - -
- Listener called when this instance emits an event for which it is registered. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
data - - -object - - - - the data passed to the listener
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.MixinBuilder.html b/docs/module-util.MixinBuilder.html deleted file mode 100644 index e944956..0000000 --- a/docs/module-util.MixinBuilder.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - JSDoc: Class: MixinBuilder - - - - - - - - - - -
- -

Class: MixinBuilder

- - - - - - -
- -
- -

- util.MixinBuilder(superclass)

- - -
- -
-
- - - - - - -

new MixinBuilder(superclass)

- - - - - - -
- Syntactic sugar for Mixins - -

This is heavily adapted from: http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
superclass - - -Object - - - -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
class BaseClass { ... }
-let Mixin1 = (superclass) => class extends superclass { ... }
-let Mixin2 = (superclass) => class extends superclass { ... }
-class NewClass extends mix(BaseClass).with(Mixin1, Mixin2) { ... }
- - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.MonotonicClock.html b/docs/module-util.MonotonicClock.html deleted file mode 100644 index 3e879ee..0000000 --- a/docs/module-util.MonotonicClock.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - JSDoc: Class: MonotonicClock - - - - - - - - - - -
- -

Class: MonotonicClock

- - - - - - -
- -
- -

- util.MonotonicClock(startTimeopt)

- - -
- -
-
- - - - - - -

new MonotonicClock(startTimeopt)

- - - - - - -
-

MonotonicClock offers a convenient way to keep track of time during experiments. An experiment can have as many independent clocks as needed, e.g. one to time responses, another one to keep track of stimuli, etc.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
startTime - - -number - - - - - - <optional>
- - - - - -
- - <time elapsed since the reference point, i.e. the time when the module was loaded> - - the clock's start time (in ms)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) getDate(locales, options) → {string}

- - - - - - -
- Get the current timestamp with language-sensitive formatting rules applied. - -

Note: This is just a convenience wrapper around `Intl.DateTimeFormat()`.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
locales - - -string -| - -array.string - - - - A string with a BCP 47 language tag, or an array of such strings.
options - - -object - - - - An object with detailed date and time styling information.
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- The current timestamp in the chosen format. -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) getDateStr() → {string}

- - - - - - -
- Get the clock's current time in the default format filtering out file name unsafe characters. - -

Note: This is mostly used as an appendix to the name of the keys save to the server.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- A string representing the current time formatted as YYYY-MM-DD_HH[h]mm.ss.sss -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getLastResetTime() → {number}

- - - - - - -
- Get the current offset being applied to the high resolution timebase used by this Clock. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the offset (in seconds) -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

getReferenceTime() → {number}

- - - - - - -
- Get the time elapsed since the reference point. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the time elapsed since the reference point (in seconds) -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

getTime() → {number}

- - - - - - -
- Get the current time on this clock. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the current time (in seconds) -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.PsychObject.html b/docs/module-util.PsychObject.html index 2760e5f..7254e49 100644 --- a/docs/module-util.PsychObject.html +++ b/docs/module-util.PsychObject.html @@ -1,23 +1,47 @@ + - JSDoc: Class: PsychObject - - - + PsychObject - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Class: PsychObject

+ + + + +
+ +

PsychObject

+ @@ -28,30 +52,79 @@
-

- util.PsychObject(psychoJS, name)

+

+ util. -

PsychoObject is the base class for all PsychoJS objects. + PsychObject +

+ +

PsychoObject is the base class for all PsychoJS objects. It is responsible for handling attributes.

-
+
+

Constructor

-

new PsychObject(psychoJS, name)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + @@ -103,7 +176,7 @@ It is responsible for handling attributes.

- the PsychoJS instance +

the PsychoJS instance

@@ -126,7 +199,7 @@ It is responsible for handling attributes.

- the name of the object (mostly useful for debugging) +

the name of the object (mostly useful for debugging)

@@ -138,76 +211,31 @@ It is responsible for handling attributes.

-
+ + + + + + + + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- -

Extends

@@ -216,10 +244,10 @@ It is responsible for handling attributes.

- + - + @@ -233,43 +261,10 @@ It is responsible for handling attributes.

-
- Get the PsychoJS instance. -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+

Get the PsychoJS instance.

+
+ + + + + + + @@ -295,46 +324,13 @@ It is responsible for handling attributes.

-
- Setter for the PsychoJS attribute. -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
@@ -343,12 +339,46 @@ It is responsible for handling attributes.

+ + + + + + + + + + + + + + + + + + + + + + + +
+
+

Setter for the PsychoJS attribute.

+
+ + + + + + + @@ -361,16 +391,59 @@ It is responsible for handling attributes.

-

(protected) _addAttribute(name, value, defaultValueopt, onChangeopt)

- -
- Add an attribute to this instance (e.g. define setters and getters) and affect a value to it. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add an attribute to this instance (e.g. define setters and getters) and affect a value to it.

@@ -381,6 +454,8 @@ It is responsible for handling attributes.

+ +
Parameters:
@@ -432,7 +507,7 @@ It is responsible for handling attributes.

- the name of the attribute +

the name of the attribute

@@ -463,7 +538,7 @@ It is responsible for handling attributes.

- the value of the attribute +

the value of the attribute

@@ -496,7 +571,7 @@ It is responsible for handling attributes.

- the default value for the attribute +

the default value for the attribute

@@ -529,7 +604,7 @@ It is responsible for handling attributes.

- function called upon changes to the attribute value +

function called upon changes to the attribute value

@@ -539,52 +614,6 @@ It is responsible for handling attributes.

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -605,16 +634,59 @@ It is responsible for handling attributes.

-

(protected) _setAttribute(attributeName, attributeValue, logopt, operationopt, stealthopt) → {boolean}

- -
- Set the value of an attribute. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Set the value of an attribute.

@@ -625,6 +697,8 @@ It is responsible for handling attributes.

+ +
Parameters:
@@ -682,7 +756,7 @@ It is responsible for handling attributes.

- the name of the attribute +

the name of the attribute

@@ -717,7 +791,7 @@ It is responsible for handling attributes.

- the value of the attribute +

the value of the attribute

@@ -751,12 +825,12 @@ It is responsible for handling attributes.

- false + false - whether of not to log +

whether of not to log

@@ -793,7 +867,7 @@ It is responsible for handling attributes.

- the binary operation such that the new value of the attribute is the result of the application of the operation to the current value of the attribute and attributeValue +

the binary operation such that the new value of the attribute is the result of the application of the operation to the current value of the attribute and attributeValue

@@ -827,12 +901,12 @@ It is responsible for handling attributes.

- false + false - whether or not to call the potential attribute setters when setting the value of this attribute +

whether or not to call the potential attribute setters when setting the value of this attribute

@@ -844,50 +918,6 @@ It is responsible for handling attributes.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -902,13 +932,13 @@ It is responsible for handling attributes.

- whether or not the value of that attribute has changed (false if the attribute -was not previously set) +

whether or not the value of that attribute has changed (false if the attribute +was not previously set)

-
+
Type
@@ -924,25 +954,69 @@ was not previously set) - - - -

toString() → {string}

- +

emit(name, data) → {boolean}

-
- String representation of the PsychObject. -

Note: attribute values are limited to 50 characters.

+
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Emit an event with a given name and associated data.

@@ -955,47 +1029,77 @@ was not previously set) +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String -
+ +

the name of the event

data + + +object + + + +

the data of the event

- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
@@ -1015,12 +1119,634 @@ was not previously set)
- the representation +

true if at least one listener has been registered for that event, and false otherwise

-
+
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + +

off(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Remove the listener with the given uuid associated to the given event name.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + + + + + + + + + +

on(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Register a new listener for events with the given name emitted by this instance.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)

+
+ + + + + + + + + + + + +

once(name, listener)

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Register a new listener for the given event name, and remove it as soon as the event has been emitted.

+
+ + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +String + + + +

the name of the event

listener + + +module:util.EventEmitter~Listener + + + +

a listener called upon emission of the event

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+

string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)

+
+ + + + + + + + + + + + +

toString() → {string}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

String representation of the PsychObject.

+

Note: attribute values are limited to 50 characters.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Returns:
+ + +
+

the representation

+
+ + + +
Type
@@ -1036,8 +1762,6 @@ was not previously set) - - @@ -1051,19 +1775,23 @@ was not previously set) + +
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) + Documentation generated by JSDoc 3.6.7 on Mon Aug 01 2022 09:56:49 GMT+0200 (Central European Summer Time) using the docdash theme.
- - + + + + + + + + \ No newline at end of file diff --git a/docs/module-util.Scheduler.html b/docs/module-util.Scheduler.html deleted file mode 100644 index 30d31ab..0000000 --- a/docs/module-util.Scheduler.html +++ /dev/null @@ -1,960 +0,0 @@ - - - - - JSDoc: Class: Scheduler - - - - - - - - - - -
- -

Class: Scheduler

- - - - - - -
- -
- -

- util.Scheduler(psychoJS)

- - -
- -
-
- - - - - - -

new Scheduler(psychoJS)

- - - - - - -
-

A scheduler helps run the main loop by managing scheduled functions, -called tasks, after each frame is displayed.

- -

-Tasks are either another Scheduler, or a -JavaScript functions returning one of the following codes: -

    -
  • Scheduler.Event.NEXT: Move onto the next task *without* rendering the scene first.
  • -
  • Scheduler.Event.FLIP_REPEAT: Render the scene and repeat the task.
  • -
  • Scheduler.Event.FLIP_NEXT: Render the scene and move onto the next task.
  • -
  • Scheduler.Event.QUIT: Quit the scheduler.
  • -
-

- -

It is possible to create sub-schedulers, e.g. to handle loops. -Sub-schedulers are added to a parent scheduler as a normal -task would be by calling scheduler.add(subScheduler).

- -

Conditional branching is also available: -scheduler.addConditionalBranches

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
psychoJS - - -module:core.PsychoJS - - - - the PsychoJS instance
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

add

- - - - -
- Schedule a new task. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

addConditional

- - - - -
- Schedule a series of task or another, based on a condition. - -

Note: the tasks are sub-schedulers.

-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(readonly) Event :Symbol

- - - - -
- Events. -
- - - -
Type:
-
    -
  • - -Symbol - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

start

- - - - -
- Start this scheduler. - -

Note: tasks are run after each animation frame.

-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

status

- - - - -
- Get the status of the scheduler. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(readonly) Status :Symbol

- - - - -
- Status. -
- - - -
Type:
-
    -
  • - -Symbol - - -
  • -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

stop

- - - - -
- Stop this scheduler. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - -

Type Definitions

- - - - - - - -

Condition() → {boolean}

- - - - - - -
- Condition evaluated when the task is run. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

Task(argsopt)

- - - - - - -
- Task to be run by the scheduler. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
args - - -* - - - - - - <optional>
- - - - - -
optional arguments
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
- - - - - \ No newline at end of file diff --git a/docs/module-util.html b/docs/module-util.html index 6e4d3bb..fa15676 100644 --- a/docs/module-util.html +++ b/docs/module-util.html @@ -1,23 +1,47 @@ + - JSDoc: Module: util - - - + util - PsychoJS API + + + + + + + + + + - - + + + + - -
+ + -

Module: util

+ + + + +
+ +

util

+ @@ -33,13 +57,15 @@
-
+
+ + +
-
@@ -49,35 +75,32 @@

Classes

-
Clock
+
Clock
-
Color
+
Color
-
CountdownTimer
+
CountdownTimer
-
EventEmitter
-
- -
MixinBuilder
-
- -
MonotonicClock
+
EventEmitter
PsychObject
-
Scheduler
+
MonotonicClock
+
+ +
Scheduler
- + - +

Mixins

@@ -89,6 +112,147 @@ +

Members

+ + + +

(static) mix

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Syntactic sugar for Mixins

+

This is heavily adapted from: http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/

+
+ + + + + + + +
Example
+ +
class BaseClass { ... }
+let Mixin1 = (superclass) => class extends superclass { ... }
+let Mixin2 = (superclass) => class extends superclass { ... }
+class NewClass extends mix(BaseClass).with(Mixin1, Mixin2) { ... }
+ + + + + +

(static, constant) TEXT_DIRECTION

+ + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Enum that stores possible text directions. +Note that Arabic is the same as RTL but added here to support PsychoPy's +languageStyle enum. Arabic reshaping is handled by the browser automatically.

+
+ + + + + + + + + +

Methods

@@ -98,17 +262,59 @@ -

(static) addInfoFromUrl(info)

- -
- Add info extracted from the URL to the given dictionary. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Add info extracted from the URL to the given dictionary.

We exclude all URL parameters starting with a double underscore since those are reserved for client/server communication

@@ -121,6 +327,8 @@ since those are reserved for client/server communication

+ +
Parameters:
@@ -162,7 +370,7 @@ since those are reserved for client/server communication

- the dictionary +

the dictionary

@@ -172,52 +380,6 @@ since those are reserved for client/server communication

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -238,18 +400,60 @@ since those are reserved for client/server communication

-

(static) average(input) → {number}

- -
- Calculate the average of the elements in the input array. -If 'input' is not an array, or if it is an empty array, then we return 0. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Calculate the average of the elements in the input array.

+

If 'input' is not an array, or if it is an empty array, then we return 0.

@@ -260,6 +464,8 @@ If 'input' is not an array, or if it is an empty array, then we return 0. + +
Parameters:
@@ -301,7 +507,7 @@ If 'input' is not an array, or if it is an empty array, then we return 0. - an array of numbers, or of objects that can be cast into a number, e.g. ['1', 2.5, 3e1] +

an array of numbers, or of objects that can be cast into a number, e.g. ['1', 2.5, 3e1]

@@ -313,50 +519,6 @@ If 'input' is not an array, or if it is an empty array, then we return 0. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -371,12 +533,12 @@ If 'input' is not an array, or if it is an empty array, then we return 0.
- the average of the elements in the array +

the average of the elements in the array

-
+
Type
@@ -392,24 +554,64 @@ If 'input' is not an array, or if it is an empty array, then we return 0. - - -

(static) count(input, value)

- -
- Count the number of elements in the input array that match the given value. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Count the number of elements in the input array that match the given value.

Note: count is able to handle NaN, null, as well as any value convertible to a JSON string.

@@ -421,6 +623,8 @@ If 'input' is not an array, or if it is an empty array, then we return 0. + +
Parameters:
@@ -462,7 +666,7 @@ If 'input' is not an array, or if it is an empty array, then we return 0. - the input array +

the input array

@@ -494,7 +698,7 @@ If 'input' is not an array, or if it is an empty array, then we return 0. - the matching value +

the matching value

@@ -506,50 +710,6 @@ If 'input' is not an array, or if it is an empty array, then we return 0. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -564,7 +724,7 @@ If 'input' is not an array, or if it is an empty array, then we return 0.
- the number of matching elements +

the number of matching elements

@@ -573,24 +733,64 @@ If 'input' is not an array, or if it is an empty array, then we return 0. - - -

(static) detectBrowser() → {string}

- -
- Detect the user's browser. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Detect the user's browser.

Note: since user agent is easily spoofed, we use a more sophisticated approach, as described here: https://stackoverflow.com/a/9851769

@@ -607,48 +807,6 @@ https://stackoverflow.com/a/9851769

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -665,13 +823,13 @@ https://stackoverflow.com/a/9851769

- the detected browser, one of 'Opera', 'Firefox', 'Safari', -'IE', 'Edge', 'EdgeChromium', 'Chrome', 'unknown' +

the detected browser, one of 'Opera', 'Firefox', 'Safari', +'IE', 'Edge', 'EdgeChromium', 'Chrome', 'unknown'

-
+
Type
@@ -687,25 +845,66 @@ https://stackoverflow.com/a/9851769

- - -

(static) extensionFromMimeType(mimeType) → {string}

- -
- Return the file extension corresponding to an audio mime type. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Return the file extension corresponding to an audio mime type. If the provided mimeType is not a string (e.g. null, undefined, an array) -or unknown, then '.dat' is returned, instead of throwing an exception. +or unknown, then '.dat' is returned, instead of throwing an exception.

@@ -716,6 +915,8 @@ or unknown, then '.dat' is returned, instead of throwing an exception. + +
Parameters:
@@ -757,7 +958,7 @@ or unknown, then '.dat' is returned, instead of throwing an exception. - the MIME type, e.g. 'audio/webm;codecs=opus' +

the MIME type, e.g. 'audio/webm;codecs=opus'

@@ -769,50 +970,6 @@ or unknown, then '.dat' is returned, instead of throwing an exception. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -827,12 +984,12 @@ or unknown, then '.dat' is returned, instead of throwing an exception.
- the corresponding file extension, e.g. '.webm' +

the corresponding file extension, e.g. '.webm'

-
+
Type
@@ -848,23 +1005,64 @@ or unknown, then '.dat' is returned, instead of throwing an exception. - - -

(static) flattenArray(array) → {Array.<Object>}

- -
- Recursively flatten an array of arrays. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Recursively flatten an array of arrays.

@@ -875,6 +1073,8 @@ or unknown, then '.dat' is returned, instead of throwing an exception. + +
Parameters:
@@ -916,7 +1116,7 @@ or unknown, then '.dat' is returned, instead of throwing an exception. - the input array of arrays +

the input array of arrays

@@ -928,50 +1128,6 @@ or unknown, then '.dat' is returned, instead of throwing an exception. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -986,12 +1142,12 @@ or unknown, then '.dat' is returned, instead of throwing an exception.
- the flatten array +

the flatten array

-
+
Type
@@ -1007,24 +1163,65 @@ or unknown, then '.dat' is returned, instead of throwing an exception. - - -

(static) getDownloadSpeed(psychoJS, nbDownloadsopt) → {number}

- -
- Get an estimate of the download speed, by repeatedly downloading an image file from a distant -server. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get an estimate of the download speed, by repeatedly downloading an image file from a distant +server.

@@ -1035,6 +1232,8 @@ server. + +
Parameters:
@@ -1092,7 +1291,7 @@ server. - the instance of PsychoJS +

the instance of PsychoJS

@@ -1126,13 +1325,13 @@ server. - 1 + 1 - the number of image downloads over which to average - the download speed +

the number of image downloads over which to average +the download speed

@@ -1144,50 +1343,6 @@ server. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1202,12 +1357,12 @@ server.
- the download speed, in megabits per second +

the download speed, in megabits per second

-
+
Type
@@ -1223,23 +1378,64 @@ server. - - -

(static) getErrorStack() → {string}

- -
- Get the error stack of the calling, exception-throwing function. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the error stack of the calling, exception-throwing function.

@@ -1254,48 +1450,6 @@ server. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -1312,12 +1466,12 @@ server.
- the error stack as a string +

the error stack as a string

-
+
Type
@@ -1333,23 +1487,64 @@ server. - - -

(static) getPositionFromObject(object, units) → {Array.<number>}

- -
- Get the position of the object, in pixel units + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the position of the object, in pixel units

@@ -1360,6 +1555,8 @@ server. + +
Parameters:
@@ -1401,7 +1598,7 @@ server. - the input object +

the input object

@@ -1424,7 +1621,7 @@ server. - the units +

the units

@@ -1436,50 +1633,6 @@ server. -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1494,12 +1647,12 @@ server.
- the position of the object, in pixel units +

the position of the object, in pixel units

-
+
Type
@@ -1515,23 +1668,64 @@ server. - - -

(static) getRequestError(jqXHR, textStatus, errorThrown)

- -
- Get the most informative error from the server response from a jquery server request. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the most informative error from the server response from a jquery server request.

@@ -1542,6 +1736,8 @@ server. + +
Parameters:
@@ -1624,52 +1820,6 @@ server. - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1690,16 +1840,59 @@ server. -

(static) getUrlParameters() → {URLSearchParams}

- -
- Get the URL parameters. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the URL parameters.

@@ -1710,49 +1903,14 @@ server. - - - - -
- +
Example
+
const urlParameters = util.getUrlParameters();
+for (const [key, value] of urlParameters)
+  console.log(key + ' = ' + value);
- - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
@@ -1772,12 +1930,12 @@ server.
- the iterable URLSearchParams +

the iterable URLSearchParams

-
+
Type
@@ -1793,31 +1951,64 @@ server. - -
Example
- -
const urlParameters = util.getUrlParameters();
-for (const [key, value] of urlParameters)
-  console.log(key + ' = ' + value);
- - - -

(static) index(input, value)

- -
- Get the index in the input array of the first element that matches the given value. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get the index in the input array of the first element that matches the given value.

Note: index is able to handle NaN, null, as well as any value convertible to a JSON string.

@@ -1829,6 +2020,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -1870,7 +2063,7 @@ for (const [key, value] of urlParameters) - the input array +

the input array

@@ -1902,7 +2095,7 @@ for (const [key, value] of urlParameters) - the matching value +

the matching value

@@ -1914,50 +2107,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -1970,9 +2119,9 @@ for (const [key, value] of urlParameters) -
+
- if the input array does not contain any matching element +

if the input array does not contain any matching element

@@ -1984,7 +2133,7 @@ for (const [key, value] of urlParameters)
- the index of the first element that matches the value +

the index of the first element that matches the value

@@ -1993,23 +2142,64 @@ for (const [key, value] of urlParameters) - - -

(static) isEmpty(x) → {boolean}

- -
- Test if x is an 'empty' value. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Test if x is an 'empty' value.

@@ -2020,6 +2210,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -2061,7 +2253,7 @@ for (const [key, value] of urlParameters) - the value to test +

the value to test

@@ -2073,50 +2265,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2131,12 +2279,12 @@ for (const [key, value] of urlParameters)
- true if x is one of the following: undefined, [], [undefined] +

true if x is one of the following: undefined, [], [undefined]

-
+
Type
@@ -2152,23 +2300,64 @@ for (const [key, value] of urlParameters) - - -

(static) isInt(obj) → {boolean}

- -
- Test whether an object is either an integer or the string representation of an integer. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Test whether an object is either an integer or the string representation of an integer.

This is adapted from: https://stackoverflow.com/a/14794066

@@ -2180,6 +2369,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -2221,7 +2412,7 @@ for (const [key, value] of urlParameters) - the input object +

the input object

@@ -2233,50 +2424,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2291,12 +2438,12 @@ for (const [key, value] of urlParameters)
- whether or not the object is an integer or the string representation of an integer +

whether or not the object is an integer or the string representation of an integer

-
+
Type
@@ -2312,23 +2459,64 @@ for (const [key, value] of urlParameters) - - -

(static) isNumeric(input) → {boolean}

- -
- Check whether a value looks like a number + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check whether a value looks like a number

@@ -2339,6 +2527,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -2380,7 +2570,7 @@ for (const [key, value] of urlParameters) - Some value +

Some value

@@ -2392,50 +2582,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2450,12 +2596,12 @@ for (const [key, value] of urlParameters)
- Whether or not the value can be converted into a number +

Whether or not the value can be converted into a number

-
+
Type
@@ -2471,23 +2617,64 @@ for (const [key, value] of urlParameters) - - -

(static) IsPointInsidePolygon(point, vertices) → {boolean}

- -
- Check whether a point lies within a polygon + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Check whether a point lies within a polygon

We are using the algorithm described here: https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html

@@ -2499,6 +2686,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -2540,7 +2729,7 @@ for (const [key, value] of urlParameters) - the point +

the point

@@ -2563,7 +2752,7 @@ for (const [key, value] of urlParameters) - the vertices defining the polygon +

the vertices defining the polygon

@@ -2575,50 +2764,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2633,12 +2778,12 @@ for (const [key, value] of urlParameters)
- whether or not the point lies within the polygon +

whether or not the point lies within the polygon

-
+
Type
@@ -2654,23 +2799,64 @@ for (const [key, value] of urlParameters) - - -

(static) makeUuid() → {string}

- -
- Get a Universally Unique Identifier (RFC4122 version 4) + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Get a Universally Unique Identifier (RFC4122 version 4)

See details here: https://www.ietf.org/rfc/rfc4122.txt

@@ -2686,48 +2872,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - @@ -2744,12 +2888,12 @@ for (const [key, value] of urlParameters)
- the uuid +

the uuid

-
+
Type
@@ -2765,23 +2909,64 @@ for (const [key, value] of urlParameters) - - -

(static) offerDataForDownload(filename, data, type)

- -
- Offer data as download in the browser. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Offer data as download in the browser.

@@ -2792,6 +2977,8 @@ for (const [key, value] of urlParameters) + +
Parameters:
@@ -2833,7 +3020,7 @@ for (const [key, value] of urlParameters) - the name of the file to be downloaded +

the name of the file to be downloaded

@@ -2856,7 +3043,7 @@ for (const [key, value] of urlParameters) - the data +

the data

@@ -2879,7 +3066,7 @@ for (const [key, value] of urlParameters) - the MIME type of the data, e.g. 'text/csv' or 'application/json' +

the MIME type of the data, e.g. 'text/csv' or 'application/json'

@@ -2889,52 +3076,6 @@ for (const [key, value] of urlParameters) - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -2955,16 +3096,60 @@ for (const [key, value] of urlParameters) - -

(static) promiseToTupple(promise) → {Array.<Object>}

- +

(static) pad(n, width) → {string}

-
- Convert the resulting value of a promise into a tupple. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Pad the given floating-point number with however many 0 needed at the start such that +the padded integer part of the number is of the given width.

@@ -2975,6 +3160,181 @@ for (const [key, value] of urlParameters) + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
n + +

the input floating-point number

width + +

the desired width

+ + + + + + + + + + + + + + + + +
Returns:
+ + +
+
    +
  • the padded number, whose integer part has the given width
  • +
+
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + +

(static) promiseToTupple(promise) → {Array.<Object>}

+ + + + + + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Convert the resulting value of a promise into a tupple.

+
+ + + + + + + + + + +
Parameters:
@@ -3016,7 +3376,7 @@ for (const [key, value] of urlParameters) - the promise +

the promise

@@ -3028,50 +3388,6 @@ for (const [key, value] of urlParameters) -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3086,13 +3402,13 @@ for (const [key, value] of urlParameters)
- the resulting value in the format [error, return data] -where error is null if there was no error +

the resulting value in the format [error, return data] +where error is null if there was no error

-
+
Type
@@ -3108,23 +3424,64 @@ where error is null if there was no error - - -

(static) randchoice(array, randomNumberGeneratoropt) → {Array.<Object>}

- -
- Pick a random value from an array, uses `util.shuffle` to shuffle the array and returns the last value. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Pick a random value from an array, uses util.shuffle to shuffle the array and returns the last value.

@@ -3135,6 +3492,8 @@ where error is null if there was no error + +
Parameters:
@@ -3186,7 +3545,7 @@ where error is null if there was no error - the input 1-D array +

the input 1-D array

@@ -3219,7 +3578,7 @@ where error is null if there was no error - A function used to generated random numbers in the interal [0, 1). Defaults to Math.random +

A function used to generated random numbers in the interal [0, 1). Defaults to Math.random

@@ -3231,50 +3590,6 @@ where error is null if there was no error -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3289,12 +3604,12 @@ where error is null if there was no error
- a chosen value from the array +

a chosen value from the array

-
+
Type
@@ -3310,23 +3625,64 @@ where error is null if there was no error - - -

(static) randint(minopt, max) → {number}

- -
- Generates random integers a-la NumPy's in the "half-open" interval [min, max). In other words, from min inclusive to max exclusive. When max is undefined, as is the case by default, results are chosen from [0, min). An error is thrown if max is less than min. + +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Generates random integers a-la NumPy's in the "half-open" interval [min, max). In other words, from min inclusive to max exclusive. When max is undefined, as is the case by default, results are chosen from [0, min). An error is thrown if max is less than min.

@@ -3337,6 +3693,8 @@ where error is null if there was no error + +
Parameters:
@@ -3393,12 +3751,12 @@ where error is null if there was no error - 0 + 0 - lowest integer to be drawn, or highest plus one if max is undefined (default) +

lowest integer to be drawn, or highest plus one if max is undefined (default)

@@ -3433,7 +3791,7 @@ where error is null if there was no error - one above the largest integer to be drawn +

one above the largest integer to be drawn

@@ -3445,50 +3803,6 @@ where error is null if there was no error -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3503,12 +3817,12 @@ where error is null if there was no error
- a random integer in the requested range (signed) +

a random integer in the requested range (signed)

-
+
Type
@@ -3524,26 +3838,65 @@ where error is null if there was no error - - -

(static) range(startopt, stop, stepopt) → {Array.<Number>}

- -
- Create a sequence of integers. -The sequence is such that the integer at index i is: start + step * i, with i >= 0 and start + step * i < stop +
+ +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Create a sequence of integers.

+

The sequence is such that the integer at index i is: start + step * i, with i >= 0 and start + step * i < stop

Note: this is a JavaScript implement of the Python range function, which explains the unusual management of arguments.

@@ -3555,6 +3908,8 @@ The sequence is such that the integer at index i is: start + step * i, with i >= + +
Parameters:
@@ -3611,12 +3966,12 @@ The sequence is such that the integer at index i is: start + step * i, with i >= - 0 + 0 - the value of start +

the value of start

@@ -3651,7 +4006,7 @@ The sequence is such that the integer at index i is: start + step * i, with i >= - the value of stop +

the value of stop

@@ -3685,12 +4040,12 @@ The sequence is such that the integer at index i is: start + step * i, with i >= - 1 + 1 - the value of step +

the value of step

@@ -3702,50 +4057,6 @@ The sequence is such that the integer at index i is: start + step * i, with i >= -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - @@ -3760,12 +4071,12 @@ The sequence is such that the integer at index i is: start + step * i, with i >=
- the range as an array of numbers +

the range as an array of numbers

-
+
Type
@@ -3781,25 +4092,72 @@ The sequence is such that the integer at index i is: start + step * i, with i >= - - -

(static) round(input, places) → {number}

- -
- Round to a certain number of decimal places. -This is the Crib Sheet provided solution, but please note that as of 2020 the most popular SO answer is different. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
See:
+
+ +
+ + + +
+ + + + + +
+

Round to a certain number of decimal places.

+

This is the Crib Sheet provided solution, but please note that as of 2020 the most popular SO answer is different.

@@ -3810,6 +4168,8 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo + +
Parameters:
@@ -3851,7 +4211,7 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo - the number to be rounded +

the number to be rounded

@@ -3874,7 +4234,7 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo - the max number of decimals desired +

the max number of decimals desired

@@ -3886,57 +4246,6 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - -
See:
-
- -
- - - -
- - - - - @@ -3951,12 +4260,12 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo
- input rounded to the specified number of decimal places at most +

input rounded to the specified number of decimal places at most

-
+
Type
@@ -3972,24 +4281,64 @@ This is the Crib Sheet provided solution, but please note that as of 2020 the mo - - -

(static) selectFromArray(array, selection) → {Object|Array.<Object>}

- -
- Select values from an array. +
+ + +
Source:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+

Select values from an array.

'selection' can be a single integer, an array of indices, or a string to be parsed, e.g.:

*

* - * @name module:core.ServerManager#getResourceStatus - * @function - * @public * @param {string | string[]} names names of the resources whose statuses are requested - * @return {core.ServerManager.ResourceStatus} status of the resource if there is only one, or reduced status otherwise + * @return {module:core.ServerManager.ResourceStatus} status of the resource if there is only one, or reduced status otherwise * @throws {Object.} if at least one of the names is not that of a previously * registered resource */ @@ -394,12 +381,8 @@ export class ServerManager extends PsychObject return reducedStatus; } - /**************************************************************************** + /** * Set the resource manager status. - * - * @name module:core.ServerManager#setStatus - * @function - * @public */ setStatus(status) { @@ -427,12 +410,9 @@ export class ServerManager extends PsychObject return this._status; } - /**************************************************************************** + /** * Reset the resource manager status to ServerManager.Status.READY. * - * @name module:core.ServerManager#resetStatus - * @function - * @public * @return {ServerManager.Status.READY} the new status */ resetStatus() @@ -440,7 +420,7 @@ export class ServerManager extends PsychObject return this.setStatus(ServerManager.Status.READY); } - /**************************************************************************** + /** * Prepare resources for the experiment: register them with the server manager and possibly * start downloading them right away. * @@ -453,10 +433,7 @@ export class ServerManager extends PsychObject *
  • If resources is null, then we do not download any resources
  • * * - * @name module:core.ServerManager#prepareResources * @param {String | Array.<{name: string, path: string, download: boolean} | String | Symbol>} [resources=[]] - the list of resources or a single resource - * @function - * @public */ async prepareResources(resources = []) { @@ -605,13 +582,10 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * Block the experiment until the specified resources have been downloaded. * - * @name module:core.ServerManager#waitForResources * @param {Array.<{name: string, path: string}>} [resources=[]] - the list of resources - * @function - * @public */ waitForResources(resources = []) { @@ -707,22 +681,18 @@ export class ServerManager extends PsychObject }; } - /**************************************************************************** + /** * @typedef ServerManager.UploadDataPromise * @property {string} origin the calling method * @property {string} context the context * @property {Object.} [error] an error message if we could not upload the data */ - /**************************************************************************** + /** * Asynchronously upload experiment data to the pavlovia server. * - * @name module:core.ServerManager#uploadData - * @function - * @public * @param {string} key - the data key (e.g. the name of .csv file) * @param {string} value - the data value (e.g. a string containing the .csv header and records) * @param {boolean} [sync= false] - whether or not to communicate with the server in a synchronous manner - * * @returns {Promise} the response */ uploadData(key, value, sync = false) @@ -780,12 +750,9 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * Asynchronously upload experiment logs to the pavlovia server. * - * @name module:core.ServerManager#uploadLog - * @function - * @public * @param {string} logs - the base64 encoded, compressed, formatted logs * @param {boolean} [compressed=false] - whether or not the logs are compressed * @returns {Promise} the response @@ -843,12 +810,9 @@ export class ServerManager extends PsychObject }); } - /**************************************************************************** + /** * Synchronously or asynchronously upload audio data to the pavlovia server. * - * @name module:core.ServerManager#uploadAudioVideo - * @function - * @public * @param @param {Object} options * @param {Blob} options.mediaBlob - the audio or video blob to be uploaded * @param {string} options.tag - additional tag @@ -978,12 +942,10 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * List the resources available to the experiment. * - * @name module:core.ServerManager#_listResources - * @function - * @private + * @protected */ _listResources() { @@ -1037,13 +999,11 @@ export class ServerManager extends PsychObject }); } - /**************************************************************************** + /** * Download the specified resources. * *

    Note: we use the [preloadjs library]{@link https://www.createjs.com/preloadjs}.

    * - * @name module:core.ServerManager#_downloadResources - * @function * @protected * @param {Set} resources - a set of names of previously registered resources */ @@ -1241,11 +1201,9 @@ export class ServerManager extends PsychObject } } - /**************************************************************************** + /** * Setup the preload.js queue, and the associated callbacks. * - * @name module:core.ServerManager#_setupPreloadQueue - * @function * @protected */ _setupPreloadQueue() @@ -1336,8 +1294,6 @@ export class ServerManager extends PsychObject /** * Query the pavlovia server API. * - * @name module:core.ServerManager#_queryServerAPI - * @function * @protected * @param method the HTTP method, i.e. GET, PUT, POST, or DELETE * @param path the resource path, without the server address @@ -1409,15 +1365,13 @@ export class ServerManager extends PsychObject } -/**************************************************************************** +/** * Server event * *

    A server event is emitted by the manager to inform its listeners of either a change of status, or of a resource related event (e.g. download started, download is completed).

    * - * @name module:core.ServerManager#Event * @enum {Symbol} * @readonly - * @public */ ServerManager.Event = { /** @@ -1443,7 +1397,7 @@ ServerManager.Event = { /** * Event: resources have all downloaded */ - DOWNLOADS_COMPLETED: Symbol.for("DOWNLOAD_COMPLETED"), + DOWNLOAD_COMPLETED: Symbol.for("DOWNLOAD_COMPLETED"), /** * Event type: status event @@ -1451,13 +1405,11 @@ ServerManager.Event = { STATUS: Symbol.for("STATUS"), }; -/**************************************************************************** +/** * Server status * - * @name module:core.ServerManager#Status * @enum {Symbol} * @readonly - * @public */ ServerManager.Status = { /** @@ -1476,13 +1428,11 @@ ServerManager.Status = { ERROR: Symbol.for("ERROR"), }; -/**************************************************************************** +/** * Resource status * - * @name module:core.ServerManager#ResourceStatus * @enum {Symbol} * @readonly - * @public */ ServerManager.ResourceStatus = { /** diff --git a/src/core/Window.js b/src/core/Window.js index 178a9fc..c666e8b 100644 --- a/src/core/Window.js +++ b/src/core/Window.js @@ -2,8 +2,8 @@ * Window responsible for displaying the experiment stimuli * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -18,20 +18,7 @@ import { Logger } from "./Logger.js"; *

    Window displays the various stimuli of the experiment.

    *

    It sets up a [PIXI]{@link http://www.pixijs.com/} renderer, which we use to render the experiment stimuli.

    * - * @name module:core.Window - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} [options.name] the name of the window - * @param {boolean} [options.fullscr= false] whether or not to go fullscreen - * @param {Color} [options.color= Color('black')] the background color of the window - * @param {number} [options.gamma= 1] sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma) - * @param {number} [options.contrast= 1] sets the contrast value - * @param {string} [options.units= 'pix'] the units of the window - * @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done - * before flipping - * @param {boolean} [options.autoLog= true] whether or not to log */ export class Window extends PsychObject { @@ -47,6 +34,20 @@ export class Window extends PsychObject return 1.0 / this.getActualFrameRate(); } + /** + * @memberof module:core + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} [options.name] the name of the window + * @param {boolean} [options.fullscr= false] whether or not to go fullscreen + * @param {Color} [options.color= Color('black')] the background color of the window + * @param {number} [options.gamma= 1] sets the divisor for gamma correction. In other words gamma correction is calculated as pow(rgb, 1/gamma) + * @param {number} [options.contrast= 1] sets the contrast value + * @param {string} [options.units= 'pix'] the units of the window + * @param {boolean} [options.waitBlanking= false] whether or not to wait for all rendering operations to be done + * before flipping + * @param {boolean} [options.autoLog= true] whether or not to log + */ constructor({ psychoJS, name, @@ -124,10 +125,6 @@ export class Window extends PsychObject * Close the window. * *

    Note: this actually only removes the canvas used to render the experiment stimuli.

    - * - * @name module:core.Window#close - * @function - * @public */ close() { @@ -161,9 +158,6 @@ export class Window extends PsychObject /** * Estimate the frame rate. * - * @name module:core.Window#getActualFrameRate - * @function - * @public * @return {number} rAF based delta time based approximation, 60.0 by default */ getActualFrameRate() @@ -177,10 +171,6 @@ export class Window extends PsychObject /** * Take the browser full screen if possible. - * - * @name module:core.Window#adjustScreenSize - * @function - * @public */ adjustScreenSize() { @@ -222,10 +212,6 @@ export class Window extends PsychObject /** * Take the browser back from full screen if needed. - * - * @name module:core.Window#closeFullScreen - * @function - * @public */ closeFullScreen() { @@ -265,9 +251,6 @@ export class Window extends PsychObject * *

    Note: the message will be time-stamped at the next call to requestAnimationFrame.

    * - * @name module:core.Window#logOnFlip - * @function - * @public * @param {Object} options * @param {String} options.msg the message to be logged * @param {module:util.Logger.ServerLevel} [level = module:util.Logger.ServerLevel.EXP] the log level @@ -294,9 +277,6 @@ export class Window extends PsychObject * *

    This is typically used to reset a timer or clock.

    * - * @name module:core.Window#callOnFlip - * @function - * @public * @param {module:core.Window~OnFlipCallback} flipCallback - callback function. * @param {...*} flipCallbackArgs - arguments for the callback function. */ @@ -307,10 +287,6 @@ export class Window extends PsychObject /** * Add PIXI.DisplayObject to the container displayed on the scene (window) - * - * @name module:core.Window#addPixiObject - * @function - * @public */ addPixiObject(pixiObject) { @@ -319,10 +295,6 @@ export class Window extends PsychObject /** * Remove PIXI.DisplayObject from the container displayed on the scene (window) - * - * @name module:core.Window#removePixiObject - * @function - * @public */ removePixiObject(pixiObject) { @@ -331,10 +303,6 @@ export class Window extends PsychObject /** * Render the stimuli onto the canvas. - * - * @name module:core.Window#render - * @function - * @public */ render() { @@ -378,9 +346,7 @@ export class Window extends PsychObject /** * Update this window, if need be. * - * @name module:core.Window#_updateIfNeeded - * @function - * @private + * @protected */ _updateIfNeeded() { @@ -403,9 +369,7 @@ export class Window extends PsychObject /** * Recompute this window's draw list and _container children for the next animation frame. * - * @name module:core.Window#_refresh - * @function - * @private + * @protected */ _refresh() { @@ -427,9 +391,7 @@ export class Window extends PsychObject /** * Force an update of all stimuli in this window's drawlist. * - * @name module:core.Window#_fullRefresh - * @function - * @private + * @protected */ _fullRefresh() { @@ -449,9 +411,7 @@ export class Window extends PsychObject *

    A new renderer is created and a container is added to it. The renderer's touch and mouse events * are handled by the {@link EventManager}.

    * - * @name module:core.Window#_setupPixi - * @function - * @private + * @protected */ _setupPixi() { @@ -523,9 +483,7 @@ export class Window extends PsychObject * Adjust the size of the renderer and the position of the root container * in response to a change in the browser's size. * - * @name module:core.Window#_resizePixiRenderer - * @function - * @private + * @protected * @param {module:core.Window} pjsWindow - the PsychoJS Window * @param event */ @@ -554,9 +512,7 @@ export class Window extends PsychObject /** * Send all logged messages to the {@link Logger}. * - * @name module:core.Window#_writeLogOnFlip - * @function - * @private + * @protected */ _writeLogOnFlip() { diff --git a/src/core/WindowMixin.js b/src/core/WindowMixin.js index e03be11..41100df 100644 --- a/src/core/WindowMixin.js +++ b/src/core/WindowMixin.js @@ -2,8 +2,8 @@ * Mixin implementing various unit-handling measurement methods. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ diff --git a/src/data/ExperimentHandler.js b/src/data/ExperimentHandler.js index 70ce3ea..2c2bebc 100644 --- a/src/data/ExperimentHandler.js +++ b/src/data/ExperimentHandler.js @@ -2,8 +2,8 @@ * Experiment Handler * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -17,22 +17,12 @@ import * as util from "../util/Util.js"; * for generating a single data file from an experiment with many different loops (e.g. interleaved * staircases or loops within loops.

    * - * @name module:data.ExperimentHandler - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} options.name - name of the experiment - * @param {Object} options.extraInfo - additional information, such as session name, participant name, etc. */ export class ExperimentHandler extends PsychObject { /** * Getter for experimentEnded. - * - * @name module:data.ExperimentHandler#experimentEnded - * @function - * @public */ get experimentEnded() { @@ -41,10 +31,6 @@ export class ExperimentHandler extends PsychObject /** * Setter for experimentEnded. - * - * @name module:data.ExperimentHandler#experimentEnded - * @function - * @public */ set experimentEnded(ended) { @@ -64,6 +50,13 @@ export class ExperimentHandler extends PsychObject return this._trialsData; } + /** + * @memberof module:data + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} options.name - name of the experiment + * @param {Object} options.extraInfo - additional information, such as session name, participant name, etc. + */ constructor({ psychoJS, name, @@ -111,9 +104,6 @@ export class ExperimentHandler extends PsychObject * Whether or not the current entry (i.e. trial data) is empty. *

    Note: this is mostly useful at the end of an experiment, in order to ensure that the last entry is saved.

    * - * @name module:data.ExperimentHandler#isEntryEmpty - * @function - * @public * @returns {boolean} whether or not the current entry is empty * @todo This really should be renamed: IsCurrentEntryNotEmpty */ @@ -128,9 +118,6 @@ export class ExperimentHandler extends PsychObject *

    The loop might be a {@link TrialHandler}, for instance.

    *

    Data from this loop will be included in the resulting data files.

    * - * @name module:data.ExperimentHandler#addLoop - * @function - * @public * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler */ addLoop(loop) @@ -143,9 +130,6 @@ export class ExperimentHandler extends PsychObject /** * Remove the given loop from the list of unfinished loops, e.g. when it has completed. * - * @name module:data.ExperimentHandler#removeLoop - * @function - * @public * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler */ removeLoop(loop) @@ -163,9 +147,6 @@ export class ExperimentHandler extends PsychObject *

    Multiple key/value pairs can be added to any given entry of the data file. There are * considered part of the same entry until a call to {@link nextEntry} is made.

    * - * @name module:data.ExperimentHandler#addData - * @function - * @public * @param {Object} key - the key * @param {Object} value - the value */ @@ -189,9 +170,6 @@ export class ExperimentHandler extends PsychObject * Inform this ExperimentHandler that the current trial has ended. Further calls to {@link addData} * will be associated with the next trial. * - * @name module:data.ExperimentHandler#nextEntry - * @function - * @public * @param {Object | Object[] | undefined} snapshots - array of loop snapshots */ nextEntry(snapshots) @@ -256,9 +234,6 @@ export class ExperimentHandler extends PsychObject * *

    * - * @name module:data.ExperimentHandler#save - * @function - * @public * @param {Object} options * @param {Array.} [options.attributes] - the attributes to be saved * @param {boolean} [options.sync=false] - whether or not to communicate with the server in a synchronous manner @@ -380,9 +355,6 @@ export class ExperimentHandler extends PsychObject * Get the attribute names and values for the current trial of a given loop. *

    Only info relating to the trial execution are returned.

    * - * @name module:data.ExperimentHandler#_getLoopAttributes - * @function - * @static * @protected * @param {Object} loop - the loop */ @@ -442,10 +414,8 @@ export class ExperimentHandler extends PsychObject /** * Experiment result format * - * @name module:core.ServerManager#SaveFormat * @enum {Symbol} * @readonly - * @public */ ExperimentHandler.SaveFormat = { /** @@ -464,7 +434,6 @@ ExperimentHandler.SaveFormat = { * * @enum {Symbol} * @readonly - * @public */ ExperimentHandler.Environment = { SERVER: Symbol.for("SERVER"), diff --git a/src/data/MultiStairHandler.js b/src/data/MultiStairHandler.js index 5c71688..a2b9b51 100644 --- a/src/data/MultiStairHandler.js +++ b/src/data/MultiStairHandler.js @@ -1,10 +1,9 @@ -/** @module data */ /** * Multiple Staircase Trial Handler * * @author Alain Pitiot - * @version 2021.2.1 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. + * @version 2021.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. * (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -22,27 +21,25 @@ import seedrandom from "seedrandom"; *

    Note that, at the moment, using the MultiStairHandler requires the jsQuest.js * library to be loaded as a resource, at the start of the experiment.

    * - * @class module.data.MultiStairHandler * @extends TrialHandler - * @param {Object} options - the handler options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} options.varName - the name of the variable / intensity / contrast - * / threshold manipulated by the staircases - * @param {module:data.MultiStairHandler.StaircaseType} [options.stairType="simple"] - the - * handler type - * @param {Array. | String} [options.conditions= [undefined] ] - if it is a string, - * we treat it as the name of a conditions resource - * @param {module:data.TrialHandler.Method} options.method - the trial method - * @param {number} [options.nTrials=50] - maximum number of trials - * @param {number} options.randomSeed - seed for the random number generator - * @param {string} options.name - name of the handler - * @param {boolean} [options.autoLog= false] - whether or not to log */ export class MultiStairHandler extends TrialHandler { /** - * @constructor - * @public + * @memberof module:data + * @param {Object} options - the handler options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} options.varName - the name of the variable / intensity / contrast + * / threshold manipulated by the staircases + * @param {MultiStairHandler.StaircaseType} [options.stairType="simple"] - the + * handler type + * @param {Array. | String} [options.conditions= [undefined] ] - if it is a string, + * we treat it as the name of a conditions resource + * @param {module:data.TrialHandler.Method} options.method - the trial method + * @param {number} [options.nTrials=50] - maximum number of trials + * @param {number} options.randomSeed - seed for the random number generator + * @param {string} options.name - name of the handler + * @param {boolean} [options.autoLog= false] - whether or not to log */ constructor({ psychoJS, @@ -91,10 +88,7 @@ export class MultiStairHandler extends TrialHandler /** * Get the current staircase. * - * @name module:data.MultiStairHandler#currentStaircase - * @function - * @public - * @returns {module.data.TrialHandler} the current staircase, or undefined if the trial has ended + * @returns {TrialHandler} the current staircase, or undefined if the trial has ended */ get currentStaircase() { @@ -104,9 +98,6 @@ export class MultiStairHandler extends TrialHandler /** * Get the current intensity. * - * @name module:data.MultiStairHandler#intensity - * @function - * @public * @returns {number} the intensity of the current staircase, or undefined if the trial has ended */ get intensity() @@ -128,13 +119,9 @@ export class MultiStairHandler extends TrialHandler /** * Add a response to the current staircase. * - * @name module:data.MultiStairHandler#addResponse - * @function - * @public * @param{number} response - the response to the trial, must be either 0 (incorrect or * non-detected) or 1 (correct or detected) * @param{number | undefined} [value] - optional intensity / contrast / threshold - * @returns {void} */ addResponse(response, value) { @@ -163,10 +150,7 @@ export class MultiStairHandler extends TrialHandler /** * Validate the conditions. * - * @name module:data.MultiStairHandler#_validateConditions - * @function * @protected - * @returns {void} */ _validateConditions() { @@ -222,10 +206,7 @@ export class MultiStairHandler extends TrialHandler /** * Setup the staircases, according to the conditions. * - * @name module:data.MultiStairHandler#_prepareStaircases - * @function * @protected - * @returns {void} */ _prepareStaircases() { @@ -282,10 +263,7 @@ export class MultiStairHandler extends TrialHandler /** * Move onto the next trial. * - * @name module:data.MultiStairHandler#_nextTrial - * @function * @protected - * @returns {void} */ _nextTrial() { @@ -425,7 +403,6 @@ export class MultiStairHandler extends TrialHandler * * @enum {Symbol} * @readonly - * @public */ MultiStairHandler.StaircaseType = { /** @@ -444,7 +421,6 @@ MultiStairHandler.StaircaseType = { * * @enum {Symbol} * @readonly - * @public */ MultiStairHandler.StaircaseStatus = { /** diff --git a/src/data/QuestHandler.js b/src/data/QuestHandler.js index 6eb9cc8..067e526 100644 --- a/src/data/QuestHandler.js +++ b/src/data/QuestHandler.js @@ -1,10 +1,9 @@ -/** @module data */ /** * Quest Trial Handler * * @author Alain Pitiot & Thomas Pronk - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -15,31 +14,29 @@ import {TrialHandler} from "./TrialHandler.js"; *

    A Trial Handler that implements the Quest algorithm for quick measurement of psychophysical thresholds. QuestHandler relies on the [jsQuest]{@link https://github.com/kurokida/jsQUEST} library, a port of Prof Dennis Pelli's QUEST algorithm by [Daiichiro Kuroki]{@link https://github.com/kurokida}.

    * - * @class module.data.QuestHandler * @extends TrialHandler - * @param {Object} options - the handler options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {string} options.varName - the name of the variable / intensity / contrast / threshold manipulated by QUEST - * @param {number} options.startVal - initial guess for the threshold - * @param {number} options.startValSd - standard deviation of the initial guess - * @param {number} options.minVal - minimum value for the threshold - * @param {number} options.maxVal - maximum value for the threshold - * @param {number} [options.pThreshold=0.82] - threshold criterion expressed as probability of getting a correct response - * @param {number} options.nTrials - maximum number of trials - * @param {number} options.stopInterval - minimum [5%, 95%] confidence interval required for the loop to stop - * @param {module:data.QuestHandler.Method} options.method - the QUEST method - * @param {number} [options.beta=3.5] - steepness of the QUEST psychometric function - * @param {number} [options.delta=0.01] - fraction of trials with blind responses - * @param {number} [options.gamma=0.5] - fraction of trails that would generate a correct response when the threshold is infinitely small - * @param {number} [options.grain=0.01] - quantization of the internal table - * @param {string} options.name - name of the handler - * @param {boolean} [options.autoLog= false] - whether or not to log */ export class QuestHandler extends TrialHandler { /** - * @constructor - * @public + * @memberof module:data + * @param {Object} options - the handler options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {string} options.varName - the name of the variable / intensity / contrast / threshold manipulated by QUEST + * @param {number} options.startVal - initial guess for the threshold + * @param {number} options.startValSd - standard deviation of the initial guess + * @param {number} options.minVal - minimum value for the threshold + * @param {number} options.maxVal - maximum value for the threshold + * @param {number} [options.pThreshold=0.82] - threshold criterion expressed as probability of getting a correct response + * @param {number} options.nTrials - maximum number of trials + * @param {number} options.stopInterval - minimum [5%, 95%] confidence interval required for the loop to stop + * @param {QuestHandler.Method} options.method - the QUEST method + * @param {number} [options.beta=3.5] - steepness of the QUEST psychometric function + * @param {number} [options.delta=0.01] - fraction of trials with blind responses + * @param {number} [options.gamma=0.5] - fraction of trails that would generate a correct response when the threshold is infinitely small + * @param {number} [options.grain=0.01] - quantization of the internal table + * @param {string} options.name - name of the handler + * @param {boolean} [options.autoLog= false] - whether or not to log */ constructor({ psychoJS, @@ -113,15 +110,11 @@ export class QuestHandler extends TrialHandler /** * Add a response and update the PDF. * - * @name module:data.QuestHandler#addResponse - * @function - * @public * @param{number} response - the response to the trial, must be either 0 (incorrect or * non-detected) or 1 (correct or detected) * @param{number | undefined} value - optional intensity / contrast / threshold * @param{boolean} [doAddData = true] - whether or not to add the response as data to the * experiment - * @returns {void} */ addResponse(response, value, doAddData = true) { @@ -163,9 +156,6 @@ export class QuestHandler extends TrialHandler /** * Simulate a response. * - * @name module:data.QuestHandler#simulate - * @function - * @public * @param{number} trueValue - the true, known value of the threshold / contrast / intensity * @returns{number} the simulated response, 0 or 1 */ @@ -184,9 +174,6 @@ export class QuestHandler extends TrialHandler /** * Get the mean of the Quest posterior PDF. * - * @name module:data.QuestHandler#mean - * @function - * @public * @returns {number} the mean */ mean() @@ -197,9 +184,6 @@ export class QuestHandler extends TrialHandler /** * Get the standard deviation of the Quest posterior PDF. * - * @name module:data.QuestHandler#sd - * @function - * @public * @returns {number} the standard deviation */ sd() @@ -210,9 +194,6 @@ export class QuestHandler extends TrialHandler /** * Get the mode of the Quest posterior PDF. * - * @name module:data.QuestHandler#mode - * @function - * @public * @returns {number} the mode */ mode() @@ -224,9 +205,6 @@ export class QuestHandler extends TrialHandler /** * Get the standard deviation of the Quest posterior PDF. * - * @name module:data.QuestHandler#quantile - * @function - * @public * @param{number} quantileOrder the quantile order * @returns {number} the quantile */ @@ -238,9 +216,6 @@ export class QuestHandler extends TrialHandler /** * Get the current value of the variable / contrast / threshold. * - * @name module:data.QuestHandler#getQuestValue - * @function - * @public * @returns {number} the current QUEST value for the variable / contrast / threshold */ getQuestValue() @@ -253,9 +228,6 @@ export class QuestHandler extends TrialHandler * *

    This is the getter associated to getQuestValue.

    * - * @name module:data.MultiStairHandler#intensity - * @function - * @public * @returns {number} the intensity of the current staircase, or undefined if the trial has ended */ get intensity() @@ -266,9 +238,6 @@ export class QuestHandler extends TrialHandler /** * Get an estimate of the 5%-95% confidence interval (CI). * - * @name module:data.QuestHandler#confInterval - * @function - * @public * @param{boolean} [getDifference=false] - if true, return the width of the CI instead of the CI * @returns{number[] | number} the 5%-95% CI or the width of the CI */ @@ -292,10 +261,7 @@ export class QuestHandler extends TrialHandler /** * Setup the JS Quest object. * - * @name module:data.QuestHandler#_setupJsQuest - * @function * @protected - * @returns {void} */ _setupJsQuest() { @@ -313,10 +279,7 @@ export class QuestHandler extends TrialHandler * Estimate the next value of the QUEST variable, based on the current value * and on the selected QUEST method. * - * @name module:data.QuestHandler#_estimateQuestValue - * @function * @protected - * @returns {void} */ _estimateQuestValue() { @@ -387,7 +350,6 @@ export class QuestHandler extends TrialHandler * * @enum {Symbol} * @readonly - * @public */ QuestHandler.Method = { /** diff --git a/src/data/Shelf.js b/src/data/Shelf.js index 20e477d..a92507c 100644 --- a/src/data/Shelf.js +++ b/src/data/Shelf.js @@ -1,9 +1,9 @@ -/** @module data */ /** * Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the - * server, and be accessed and manipulated in a concurrent fashion. + * server, and can be accessed and manipulated in a concurrent fashion. * * @author Alain Pitiot + * @version 2021.2.3 * @copyright (c) 2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -16,27 +16,25 @@ import {Scheduler} from "../util/Scheduler.js"; /** *

    Shelf handles persistent key/value pairs, or records, which are stored in the shelf collection on the - * server, and be accessed and manipulated in a concurrent fashion.

    + * server, and can be accessed and manipulated in a concurrent fashion.

    * - *

    - * - * @name module:data.Shelf - * @class * @extends PsychObject - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS the PsychoJS instance - * @param {boolean} [options.autoLog= false] whether to log */ export class Shelf extends PsychObject { /** * Maximum number of components in a key - * @name module:data.Shelf.#MAX_KEY_LENGTH * @type {number} * @note this value should mirror that on the server, i.e. the server also checks that the key is valid */ static #MAX_KEY_LENGTH = 10; + /** + * @memberOf module:data + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS the PsychoJS instance + * @param {boolean} [options.autoLog= false] whether to log + */ constructor({psychoJS, autoLog = false } = {}) { super(psychoJS); @@ -56,9 +54,6 @@ export class Shelf extends PsychObject /** * Get the value of a record of type BOOLEAN associated with the given key. * - * @name module:data.Shelf#getBooleanValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {boolean} options.defaultValue the default value returned if no record with the given key exists @@ -75,9 +70,6 @@ export class Shelf extends PsychObject /** * Set the value of a record of type BOOLEAN associated with the given key. * - * @name module:data.Shelf#setBooleanValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {boolean} options.value the new value @@ -108,9 +100,6 @@ export class Shelf extends PsychObject /** * Flip the value of a record of type BOOLEAN associated with the given key. * - * @name module:data.Shelf#flipBooleanValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @return {Promise} the new, flipped, value @@ -129,9 +118,6 @@ export class Shelf extends PsychObject /** * Get the value of a record of type INTEGER associated with the given key. * - * @name module:data.Shelf#getIntegerValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {number} options.defaultValue the default value returned if no record with the given key @@ -148,9 +134,6 @@ export class Shelf extends PsychObject /** * Set the value of a record of type INTEGER associated with the given key. * - * @name module:data.Shelf#setIntegerValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {number} options.value the new value @@ -181,9 +164,6 @@ export class Shelf extends PsychObject /** * Add a delta to the value of a record of type INTEGER associated with the given key. * - * @name module:data.Shelf#addIntegerValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {number} options.delta the delta, positive or negative, to add to the value @@ -214,9 +194,6 @@ export class Shelf extends PsychObject /** * Get the value of a record of type TEXT associated with the given key. * - * @name module:data.Shelf#getTextValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {string} options.defaultValue the default value returned if no record with the given key exists on @@ -233,9 +210,6 @@ export class Shelf extends PsychObject /** * Set the value of a record of type TEXT associated with the given key. * - * @name module:data.Shelf#setTextValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {string} options.value the new value @@ -266,9 +240,6 @@ export class Shelf extends PsychObject /** * Get the value of a record of type LIST associated with the given key. * - * @name module:data.Shelf#getListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {Array.<*>} options.defaultValue the default value returned if no record with the given key exists on @@ -285,9 +256,6 @@ export class Shelf extends PsychObject /** * Set the value of a record of type LIST associated with the given key. * - * @name module:data.Shelf#setListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {Array.<*>} options.value the new value @@ -318,9 +286,6 @@ export class Shelf extends PsychObject /** * Append an element, or a list of elements, to the value of a record of type LIST associated with the given key. * - * @name module:data.Shelf#appendListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {*} options.elements the element or list of elements to be appended @@ -342,9 +307,6 @@ export class Shelf extends PsychObject * Pop an element, at the given index, from the value of a record of type LIST associated * with the given key. * - * @name module:data.Shelf#popListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {number} [options.index = -1] the index of the element to be popped @@ -365,9 +327,6 @@ export class Shelf extends PsychObject /** * Empty the value of a record of type LIST associated with the given key. * - * @name module:data.Shelf#clearListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @return {Promise>} the new, empty value, i.e. [] @@ -386,9 +345,6 @@ export class Shelf extends PsychObject /** * Shuffle the elements of the value of a record of type LIST associated with the given key. * - * @name module:data.Shelf#shuffleListValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @return {Promise>} the new, shuffled value @@ -408,9 +364,6 @@ export class Shelf extends PsychObject /** * Get the names of the fields in the dictionary record associated with the given key. * - * @name module:data.Shelf#getDictionaryFieldNames - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @return {Promise} the list of field names @@ -425,9 +378,6 @@ export class Shelf extends PsychObject /** * Get the value of a given field in the dictionary record associated with the given key. * - * @name module:data.Shelf#getDictionaryFieldValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {string} options.fieldName the name of the field @@ -445,9 +395,6 @@ export class Shelf extends PsychObject /** * Set a field in the dictionary record associated to the given key. * - * @name module:data.Shelf#setDictionaryFieldValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {string} options.fieldName the name of the field @@ -470,9 +417,6 @@ export class Shelf extends PsychObject /** * Get the value of a record of type DICTIONARY associated with the given key. * - * @name module:data.Shelf#getDictionaryValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {Object.} options.defaultValue the default value returned if no record with the given key @@ -489,9 +433,6 @@ export class Shelf extends PsychObject /** * Set the value of a record of type DICTIONARY associated with the given key. * - * @name module:data.Shelf#setDictionaryValue - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {Object.} options.value the new value @@ -523,9 +464,6 @@ export class Shelf extends PsychObject * Schedulable component that will block the experiment until the counter associated with the given key * has been incremented by the given amount. * - * @name module:data.Shelf#incrementComponent - * @function - * @public * @param key * @param increment * @param callback @@ -576,9 +514,6 @@ export class Shelf extends PsychObject /** * Get the name of a group, using a counterbalanced design. * - * @name module:data.Shelf#counterBalanceSelect - * @function - * @public * @param {Object} options * @param {string[]} options.key key as an array of key components * @param {string[]} options.groups the names of the groups @@ -648,9 +583,6 @@ export class Shelf extends PsychObject * *

    This is a generic method, typically called from the Shelf helper methods, e.g. setBinaryValue.

    * - * @name module:data.Shelf#_updateValue - * @function - * @protected * @param {string[]} key key as an array of key components * @param {Shelf.Type} type the type of the record associated with the given key * @param {*} update the desired update @@ -716,9 +648,6 @@ export class Shelf extends PsychObject * *

    This is a generic method, typically called from the Shelf helper methods, e.g. getBinaryValue.

    * - * @name module:data.Shelf#_getValue - * @function - * @protected * @param {string[]} key key as an array of key components * @param {Shelf.Type} type the type of the record associated with the given key * @param {Object} [options] the options, e.g. the default value returned if no record with the @@ -794,16 +723,8 @@ export class Shelf extends PsychObject * *

    Since all Shelf methods call _checkAvailability, we also use it as a means to throttle those calls.

    * - * @name module:data.Shelf#_checkAvailability - * @function - * @public -<<<<<<< HEAD - * @param {string} [methodName=""] name of the method requiring a check - * @throws {Object.} exception if it is not possible to run the given shelf command -======= - * @param {string} [methodName=""] name of the method requiring a check - * @throw {Object.} exception when it is not possible to run the given shelf command ->>>>>>> 8cc27b9cc9844d435c0177263ef7c2991463196c + * @param {string} [methodName=""] - name of the method requiring a check + * @throws {Object.} exception if it is not possible to run the given shelf command */ _checkAvailability(methodName = "") { @@ -852,9 +773,6 @@ export class Shelf extends PsychObject /** * Check the validity of the key. * - * @name module:data.Shelf#_checkKey - * @function - * @public * @param {object} key key whose validity is to be checked * @throws {Object.} exception if the key is invalid */ @@ -879,10 +797,8 @@ export class Shelf extends PsychObject /** * Shelf status * - * @name module:data.Shelf#Status * @enum {Symbol} * @readonly - * @public */ Shelf.Status = { /** @@ -906,7 +822,6 @@ Shelf.Status = { * * @enum {Symbol} * @readonly - * @public */ Shelf.Type = { INTEGER: Symbol.for('INTEGER'), diff --git a/src/data/TrialHandler.js b/src/data/TrialHandler.js index 0dd189a..c531d7d 100644 --- a/src/data/TrialHandler.js +++ b/src/data/TrialHandler.js @@ -4,8 +4,8 @@ * * @author Alain Pitiot * @author Hiroyuki Sogo & Sotiri Bakagiannis - better support for BOM and accented characters - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -17,25 +17,12 @@ import * as util from "../util/Util.js"; /** *

    A Trial Handler handles the importing and sequencing of conditions.

    * - * @class * @extends PsychObject - * @param {Object} options - the handler options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {Array. | String} [options.trialList= [undefined] ] - if it is a string, we treat it as the name of a condition resource - * @param {number} options.nReps - number of repetitions - * @param {module:data.TrialHandler.Method} options.method - the trial method - * @param {Object} options.extraInfo - additional information to be stored alongside the trial data, e.g. session ID, participant ID, etc. - * @param {number} options.seed - seed for the random number generator - * @param {boolean} [options.autoLog= false] - whether or not to log */ export class TrialHandler extends PsychObject { /** * Getter for experimentHandler. - * - * @name module:core.Window#experimentHandler - * @function - * @public */ get experimentHandler() { @@ -44,10 +31,6 @@ export class TrialHandler extends PsychObject /** * Setter for experimentHandler. - * - * @name module:core.Window#experimentHandler - * @function - * @public */ set experimentHandler(exp) { @@ -55,8 +38,14 @@ export class TrialHandler extends PsychObject } /** - * @constructor - * @public + * @param {Object} options - the handler options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {Array. | String} [options.trialList= [undefined] ] - if it is a string, we treat it as the name of a condition resource + * @param {number} options.nReps - number of repetitions + * @param {module:data.TrialHandler.Method} options.method - the trial method + * @param {Object} options.extraInfo - additional information to be stored alongside the trial data, e.g. session ID, participant ID, etc. + * @param {number} options.seed - seed for the random number generator + * @param {boolean} [options.autoLog= false] - whether or not to log * * @todo extraInfo is not taken into account, we use the expInfo of the ExperimentHandler instead */ @@ -223,7 +212,6 @@ export class TrialHandler extends PsychObject * *

    This is typically used in the LoopBegin function, in order to capture the current state of a TrialHandler

    * - * @public * @return {Snapshot} - a snapshot of the current internal state. */ getSnapshot() @@ -296,8 +284,6 @@ export class TrialHandler extends PsychObject /** * Set the internal state of the snapshot's trial handler from the snapshot. * - * @public - * @static * @param {Snapshot} snapshot - the snapshot from which to update the current internal state of the * snapshot's trial handler */ @@ -365,7 +351,6 @@ export class TrialHandler extends PsychObject /** * Get the trial index. * - * @public * @return {number} the current trial index */ getTrialIndex() @@ -389,7 +374,6 @@ export class TrialHandler extends PsychObject *

    Note: we assume that all trials in the trialList share the same attributes * and consequently consider only the attributes of the first trial.

    * - * @public * @return {Array.string} the attributes */ getAttributes() @@ -411,7 +395,6 @@ export class TrialHandler extends PsychObject /** * Get the current trial. * - * @public * @return {Object} the current trial */ getCurrentTrial() @@ -438,7 +421,6 @@ export class TrialHandler extends PsychObject /** * Get the nth future or past trial, without advancing through the trial list. * - * @public * @param {number} [n = 1] - increment * @return {Object|undefined} the future trial (if n is positive) or past trial (if n is negative) * or undefined if attempting to go beyond the last trial. @@ -457,7 +439,6 @@ export class TrialHandler extends PsychObject * Get the nth previous trial. *

    Note: this is useful for comparisons in n-back tasks.

    * - * @public * @param {number} [n = -1] - increment * @return {Object|undefined} the past trial or undefined if attempting to go prior to the first trial. */ @@ -469,7 +450,6 @@ export class TrialHandler extends PsychObject /** * Add a key/value pair to data about the current trial held by the experiment handler * - * @public * @param {Object} key - the key * @param {Object} value - the value */ @@ -508,8 +488,6 @@ export class TrialHandler extends PsychObject * '5:' * '-5:-2, 9, 11:5:22' * - * @public - * @static * @param {module:core.ServerManager} serverManager - the server manager * @param {String} resourceName - the name of the resource containing the list of conditions, which must have been registered with the server manager. * @param {Object} [selection = null] - the selection @@ -617,7 +595,6 @@ export class TrialHandler extends PsychObject /** * Prepare the trial list. * - * @function * @protected * @returns {void} */ @@ -655,7 +632,7 @@ export class TrialHandler extends PsychObject } } - /* + /** * Prepare the sequence of trials. * *

    The returned sequence is a matrix (an array of arrays) of trial indices @@ -680,7 +657,7 @@ export class TrialHandler extends PsychObject *

    * * @protected - */ + **/ _prepareSequence() { const response = { @@ -738,7 +715,6 @@ export class TrialHandler extends PsychObject * * @enum {Symbol} * @readonly - * @public */ TrialHandler.Method = { /** diff --git a/src/data/index.js b/src/data/index.js index bd13927..1bffe5e 100644 --- a/src/data/index.js +++ b/src/data/index.js @@ -2,5 +2,4 @@ export * from "./ExperimentHandler.js"; export * from "./TrialHandler.js"; export * from "./QuestHandler.js"; export * from "./MultiStairHandler.js"; -//export * from "./Shelf.js"; export * from "./Shelf.js"; diff --git a/src/hardware/Camera.js b/src/hardware/Camera.js index c790c92..8d3b1c2 100644 --- a/src/hardware/Camera.js +++ b/src/hardware/Camera.js @@ -1,9 +1,10 @@ +/** **/ /** * Manager handling the recording of video signal. * * @author Alain Pitiot * @version 2022.2.0 - * @copyright (c) 2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @copyright (c) 2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ diff --git a/src/index.css b/src/index.css index 01475ef..00f232b 100644 --- a/src/index.css +++ b/src/index.css @@ -95,6 +95,11 @@ a:hover { transform: translate(-50%, -50%); } +#root.is-ready::after +{ + content: "" +} + .dialog-container, .dialog-overlay { @@ -144,6 +149,14 @@ a:hover { border-radius: 2px; } +.dialog-warning { + background-color: #FF9900 !important; +} + +.dialog-error { + background-color: #FF0000 !important; +} + .dialog-title p { margin: 0; padding: 0; diff --git a/src/sound/AudioClip.js b/src/sound/AudioClip.js index f21dd0f..d8d675b 100644 --- a/src/sound/AudioClip.js +++ b/src/sound/AudioClip.js @@ -2,7 +2,7 @@ * AudioClip encapsulates an audio recording. * * @author Alain Pitiot and Sotiri Bakagiannis - * @version 2021.2.0 + * @version 2022.2.3 * @copyright (c) 2021 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -15,18 +15,20 @@ import * as util from "../util/Util.js"; /** *

    AudioClip encapsulates an audio recording.

    * - * @name module:sound.AudioClip - * @class - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {String} [options.name= 'audioclip'] - the name used when logging messages - * @param {string} options.format the format for the audio file - * @param {number} options.sampleRateHz - the sampling rate - * @param {Blob} options.data - the audio data, in the given format, at the given sampling rate - * @param {boolean} [options.autoLog= false] - whether or not to log + * @extends PsychObject */ export class AudioClip extends PsychObject { + /** + * @memberOf module:sound + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {String} [options.name= 'audioclip'] - the name used when logging messages + * @param {string} options.format the format for the audio file + * @param {number} options.sampleRateHz - the sampling rate + * @param {Blob} options.data - the audio data, in the given format, at the given sampling rate + * @param {boolean} [options.autoLog= false] - whether or not to log + */ constructor({ psychoJS, name, sampleRateHz, format, data, autoLog } = {}) { super(psychoJS); @@ -53,9 +55,6 @@ export class AudioClip extends PsychObject /** * Set the volume of the playback. * - * @name module:sound.AudioClip#setVolume - * @function - * @public * @param {number} volume - the volume of the playback (must be between 0.0 and 1.0) */ setVolume(volume) @@ -66,8 +65,6 @@ export class AudioClip extends PsychObject /** * Start playing the audio clip. * - * @name module:sound.AudioClip#startPlayback - * @function * @public */ async startPlayback() @@ -102,9 +99,6 @@ export class AudioClip extends PsychObject /** * Stop playing the audio clip. * - * @name module:sound.AudioClip#startPlayback - * @function - * @public * @param {number} [fadeDuration = 17] - how long the fading out should last, in ms */ async stopPlayback(fadeDuration = 17) @@ -118,9 +112,6 @@ export class AudioClip extends PsychObject /** * Get the duration of the audio clip, in seconds. * - * @name module:sound.AudioClip#getDuration - * @function - * @public * @returns {Promise} the duration of the audio clip */ async getDuration() @@ -134,8 +125,6 @@ export class AudioClip extends PsychObject /** * Upload the audio clip to the pavlovia server. * - * @name module:sound.AudioClip#upload - * @function * @public */ upload() @@ -165,10 +154,6 @@ export class AudioClip extends PsychObject /** * Offer the audio clip to the participant as a sound file to download. - * - * @name module:sound.AudioClip#download - * @function - * @public */ download(filename = "audio.webm") { @@ -239,6 +224,7 @@ export class AudioClip extends PsychObject * * ref: https://cloud.google.com/speech-to-text/docs/reference/rest/v1/speech/recognize * + * @protected * @param {String} transcriptionKey - the secret key to the Google service * @param {String} languageCode - the BCP-47 language code for the recognition, e.g. 'en-GB' * @return {Promise} a promise resolving to the transcript and associated @@ -306,6 +292,7 @@ export class AudioClip extends PsychObject /** * Decode the formatted audio data (e.g. webm) into a 32bit float PCM audio buffer. * + * @protected */ _decodeAudio() { @@ -386,6 +373,7 @@ export class AudioClip extends PsychObject * const dataAsString = String.fromCharCode.apply(null, new Uint8Array(buffer)); * base64Data = window.btoa(dataAsString); * + * @protected * @param arrayBuffer - the input buffer * @return {string} the base64 encoded input buffer */ @@ -453,10 +441,8 @@ export class AudioClip extends PsychObject /** * Recognition engines. * - * @name module:sound.AudioClip#Engine * @enum {Symbol} * @readonly - * @public */ AudioClip.Engine = { /** @@ -470,7 +456,6 @@ AudioClip.Engine = { * * @enum {Symbol} * @readonly - * @public */ AudioClip.Status = { CREATED: Symbol.for("CREATED"), diff --git a/src/sound/AudioClipPlayer.js b/src/sound/AudioClipPlayer.js index 082a71a..10dd99b 100644 --- a/src/sound/AudioClipPlayer.js +++ b/src/sound/AudioClipPlayer.js @@ -2,8 +2,8 @@ * AudioClip Player. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -13,20 +13,21 @@ import { SoundPlayer } from "./SoundPlayer.js"; /** *

    This class handles the playback of an audio clip, e.g. a microphone recording.

    * - * @name module:sound.AudioClipPlayer - * @class * @extends SoundPlayer - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {Object} options.audioClip - the module:sound.AudioClip - * @param {number} [options.startTime= 0] - start of playback (in seconds) - * @param {number} [options.stopTime= -1] - end of playback (in seconds) - * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo - * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) - * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played * */ export class AudioClipPlayer extends SoundPlayer { + /** + * @memberOf module:sound + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {Object} options.audioClip - the module:sound.AudioClip + * @param {number} [options.startTime= 0] - start of playback (in seconds) + * @param {number} [options.stopTime= -1] - end of playback (in seconds) + * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo + * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) + * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played * + */ constructor({ psychoJS, audioClip, @@ -52,10 +53,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Determine whether this player can play the given sound. * - * @name module:sound.AudioClipPlayer.accept - * @function - * @static - * @public * @param {module:sound.Sound} sound - the sound object, which should be an AudioClip * @return {Object|undefined} an instance of AudioClipPlayer if sound is an AudioClip or undefined otherwise */ @@ -83,9 +80,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Get the duration of the AudioClip, in seconds. * - * @name module:sound.AudioClipPlayer#getDuration - * @function - * @public * @return {number} the duration of the clip, in seconds */ getDuration() @@ -96,9 +90,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Set the duration of the audio clip. * - * @name module:sound.AudioClipPlayer#setDuration - * @function - * @public * @param {number} duration_s - the duration of the clip in seconds */ setDuration(duration_s) @@ -115,9 +106,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Set the volume of the playback. * - * @name module:sound.AudioClipPlayer#setVolume - * @function - * @public * @param {number} volume - the volume of the playback (must be between 0.0 and 1.0) * @param {boolean} [mute= false] - whether or not to mute the playback */ @@ -131,9 +119,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Set the number of loops. * - * @name module:sound.AudioClipPlayer#setLoops - * @function - * @public * @param {number} loops - how many times to repeat the clip after it has played once. If loops == -1, the clip will repeat indefinitely until stopped. */ setLoops(loops) @@ -147,9 +132,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Start playing the sound. * - * @name module:sound.AudioClipPlayer#play - * @function - * @public * @param {number} loops - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped. * @param {number} [fadeDuration = 17] - how long should the fading in last in ms */ @@ -172,9 +154,6 @@ export class AudioClipPlayer extends SoundPlayer /** * Stop playing the sound immediately. * - * @name module:sound.AudioClipPlayer#stop - * @function - * @public * @param {number} [fadeDuration = 17] - how long the fading out should last, in ms */ stop(fadeDuration = 17) diff --git a/src/sound/Microphone.js b/src/sound/Microphone.js index 2f839c6..1d1f9d3 100644 --- a/src/sound/Microphone.js +++ b/src/sound/Microphone.js @@ -2,8 +2,8 @@ * Manager handling the recording of audio signal. * * @author Alain Pitiot and Sotiri Bakagiannis - * @version 2021.2.0 - * @copyright (c) 2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -17,18 +17,20 @@ import { AudioClip } from "./AudioClip.js"; /** *

    This manager handles the recording of audio signal.

    * - * @name module:sound.Microphone - * @class - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param @param {module:core.Window} options.win - the associated Window - * @param {string} [options.format='audio/webm;codecs=opus'] the format for the audio file - * @param {number} [options.sampleRateHz= 48000] - the audio sampling rate, in Hz - * @param {Clock} [options.clock= undefined] - an optional clock - * @param {boolean} [options.autoLog= false] - whether or not to log + * @extends PsychObject */ export class Microphone extends PsychObject { + /** + * @memberOf module:sound + * @param {Object} options + * @param {module:core.Window} options.win - the associated Window + * @param {String} options.name - the name used when logging messages from this stimulus + * @param {string} [options.format='audio/webm;codecs=opus'] the format for the audio file + * @param {number} [options.sampleRateHz= 48000] - the audio sampling rate, in Hz + * @param {Clock} [options.clock= undefined] - an optional clock + * @param {boolean} [options.autoLog= false] - whether to log + */ constructor({ win, name, format, sampleRateHz, clock, autoLog } = {}) { super(win._psychoJS); @@ -56,8 +58,6 @@ export class Microphone extends PsychObject *

    Note that it typically takes 50ms-200ms for the recording to actually starts once * a request to start has been submitted.

    * - * @name module:sound.Microphone#start - * @public * @return {Promise} promise fulfilled when the recording actually started */ start() @@ -108,8 +108,6 @@ export class Microphone extends PsychObject /** * Submit a request to stop the recording. * - * @name module:sound.Microphone#stop - * @public * @param {Object} options * @param {string} [options.filename] the name of the file to which the audio recording will be * saved @@ -145,8 +143,6 @@ export class Microphone extends PsychObject /** * Submit a request to pause the recording. * - * @name module:sound.Microphone#pause - * @public * @return {Promise} promise fulfilled when the recording actually paused */ pause() @@ -192,7 +188,6 @@ export class Microphone extends PsychObject * *

    resume has no effect if the recording was not previously paused.

    * - * @name module:sound.Microphone#resume * @param {Object} options * @param {boolean} [options.clear= false] whether or not to empty the audio buffer before * resuming the recording @@ -245,8 +240,6 @@ export class Microphone extends PsychObject /** * Submit a request to flush the recording. * - * @name module:sound.Microphone#flush - * @public * @return {Promise} promise fulfilled when the data has actually been made available */ flush() @@ -273,9 +266,6 @@ export class Microphone extends PsychObject /** * Offer the audio recording to the participant as a sound file to download. * - * @name module:sound.Microphone#download - * @function - * @public * @param {string} filename the filename */ download(filename = "audio.webm") @@ -293,9 +283,6 @@ export class Microphone extends PsychObject /** * Upload the audio recording to the pavlovia server. * - * @name module:sound.Microphone#upload - * @function - * @public * @param {string} tag an optional tag for the audio file */ async upload({ tag } = {}) @@ -331,9 +318,6 @@ export class Microphone extends PsychObject /** * Get the current audio recording as an AudioClip in the given format. * - * @name module:sound.Microphone#getRecording - * @function - * @public * @param {string} tag an optional tag for the audio clip * @param {boolean} [flush=false] whether or not to first flush the recording */ @@ -361,8 +345,6 @@ export class Microphone extends PsychObject * *

    Changes to the settings require the recording to stop and be re-started.

    * - * @name module:sound.Microphone#_onChange - * @function * @protected */ _onChange() @@ -380,8 +362,6 @@ export class Microphone extends PsychObject /** * Prepare the recording. * - * @name module:sound.Microphone#_prepareRecording - * @function * @protected */ async _prepareRecording() diff --git a/src/sound/Sound.js b/src/sound/Sound.js index 51f1b01..cf4ef45 100644 --- a/src/sound/Sound.js +++ b/src/sound/Sound.js @@ -3,8 +3,8 @@ * Sound stimulus. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -35,23 +35,24 @@ import { TrackPlayer } from "./TrackPlayer.js"; * track.setVolume(1.0); * track.play(2); * - * @class * @extends PsychObject - * @param {Object} options - * @param {String} options.name - the name used when logging messages from this stimulus - * @param {module:core.Window} options.win - the associated Window - * @param {number|string} [options.value= 'C'] - the sound value (see above for a full description) - * @param {number} [options.octave= 4] - the octave corresponding to the tone (if applicable) - * @param {number} [options.secs= 0.5] - duration of the tone (in seconds) If secs == -1, the sound will play indefinitely. - * @param {number} [options.startTime= 0] - start of playback for tracks (in seconds) - * @param {number} [options.stopTime= -1] - end of playback for tracks (in seconds) - * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo - * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) - * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played once. If loops == -1, the track or tone will repeat indefinitely until stopped. - * @param {boolean} [options.autoLog= true] whether or not to log */ export class Sound extends PsychObject { + /** + * @param {Object} options + * @param {String} options.name - the name used when logging messages from this stimulus + * @param {module:core.Window} options.win - the associated Window + * @param {number|string} [options.value= 'C'] - the sound value (see above for a full description) + * @param {number} [options.octave= 4] - the octave corresponding to the tone (if applicable) + * @param {number} [options.secs= 0.5] - duration of the tone (in seconds) If secs == -1, the sound will play indefinitely. + * @param {number} [options.startTime= 0] - start of playback for tracks (in seconds) + * @param {number} [options.stopTime= -1] - end of playback for tracks (in seconds) + * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo + * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) + * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played once. If loops == -1, the track or tone will repeat indefinitely until stopped. + * @param {boolean} [options.autoLog= true] whether or not to log + */ constructor({ name, win, @@ -95,7 +96,6 @@ export class Sound extends PsychObject *

    Note: Sounds are played independently from the stimuli of the experiments, i.e. the experiment will not stop until the sound is finished playing. * Repeat calls to play may results in the sounds being played on top of each other.

    * - * @public * @param {number} loops how many times to repeat the sound after it plays once. If loops == -1, the sound will repeat indefinitely until stopped. * @param {boolean} [log= true] whether or not to log */ @@ -108,7 +108,6 @@ export class Sound extends PsychObject /** * Stop playing the sound immediately. * - * @public * @param {Object} options * @param {boolean} [options.log= true] - whether or not to log */ @@ -123,7 +122,6 @@ export class Sound extends PsychObject /** * Get the duration of the sound, in seconds. * - * @public * @return {number} the duration of the sound, in seconds */ getDuration() @@ -134,7 +132,6 @@ export class Sound extends PsychObject /** * Set the playing volume of the sound. * - * @public * @param {number} volume - the volume (values should be between 0 and 1) * @param {boolean} [mute= false] - whether or not to mute the sound * @param {boolean} [log= true] - whether of not to log @@ -152,7 +149,6 @@ export class Sound extends PsychObject /** * Set the sound value on demand past initialisation. * - * @public * @param {object} sound - a sound instance to replace the current one * @param {boolean} [log= true] - whether or not to log */ @@ -181,7 +177,6 @@ export class Sound extends PsychObject /** * Set the number of loops. * - * @public * @param {number} [loops=0] - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped. * @param {boolean} [log=true] - whether of not to log */ @@ -198,7 +193,6 @@ export class Sound extends PsychObject /** * Set the duration (in seconds) * - * @public * @param {number} [secs=0.5] - duration of the tone (in seconds) If secs == -1, the sound will play indefinitely. * @param {boolean} [log=true] - whether or not to log */ diff --git a/src/sound/SoundPlayer.js b/src/sound/SoundPlayer.js index 4ba5bdb..512c365 100644 --- a/src/sound/SoundPlayer.js +++ b/src/sound/SoundPlayer.js @@ -2,8 +2,8 @@ * Sound player interface * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -12,13 +12,15 @@ import { PsychObject } from "../util/PsychObject.js"; /** *

    SoundPlayer is an interface for the sound players, who are responsible for actually playing the sounds, i.e. the tracks or the tones.

    * - * @name module:sound.SoundPlayer * @interface * @extends PsychObject - * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance */ export class SoundPlayer extends PsychObject { + /** + * @memberOf module:sound + * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance + */ constructor(psychoJS) { super(psychoJS); @@ -27,10 +29,6 @@ export class SoundPlayer extends PsychObject /** * Determine whether this player can play the given sound. * - * @name module:sound.SoundPlayer.accept - * @function - * @static - * @public * @abstract * @param {module:sound.Sound} - the sound * @return {Object|undefined} an instance of the SoundPlayer that can play the sound, or undefined if none could be found @@ -47,9 +45,6 @@ export class SoundPlayer extends PsychObject /** * Start playing the sound. * - * @name module:sound.SoundPlayer#play - * @function - * @public * @abstract * @param {number} [loops] - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped. */ @@ -65,9 +60,6 @@ export class SoundPlayer extends PsychObject /** * Stop playing the sound immediately. * - * @name module:sound.SoundPlayer#stop - * @function - * @public * @abstract */ stop() @@ -82,9 +74,6 @@ export class SoundPlayer extends PsychObject /** * Get the duration of the sound, in seconds. * - * @name module:sound.SoundPlayer#getDuration - * @function - * @public * @abstract */ getDuration() @@ -99,9 +88,6 @@ export class SoundPlayer extends PsychObject /** * Set the duration of the sound, in seconds. * - * @name module:sound.SoundPlayer#setDuration - * @function - * @public * @abstract */ setDuration(duration_s) @@ -116,9 +102,6 @@ export class SoundPlayer extends PsychObject /** * Set the number of loops. * - * @name module:sound.SoundPlayer#setLoops - * @function - * @public * @abstract * @param {number} loops - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped. */ @@ -134,9 +117,6 @@ export class SoundPlayer extends PsychObject /** * Set the volume of the tone. * - * @name module:sound.SoundPlayer#setVolume - * @function - * @public * @abstract * @param {Integer} volume - the volume of the tone * @param {boolean} [mute= false] - whether or not to mute the tone diff --git a/docs/sound_Transcriber.js.html b/src/sound/SpeechRecognition.js similarity index 53% rename from docs/sound_Transcriber.js.html rename to src/sound/SpeechRecognition.js index 2457c9c..53dfee3 100644 --- a/docs/sound_Transcriber.js.html +++ b/src/sound/SpeechRecognition.js @@ -1,37 +1,9 @@ - - - - - JSDoc: Source: sound/Transcriber.js - - - - - - - - - - -
    - -

    Source: sound/Transcriber.js

    - - - - - - -
    -
    -
    /**
    - * Manager handling the transcription of Speech into Text.
    +/**
    + * Manager handling the live transcription of speech into text.
      *
    - * @author Sotiri Bakagiannis and Alain Pitiot
    - * @version 2021.2.0
    - * @copyright (c) 2021 Open Science Tools Ltd. (https://opensciencetools.org)
    + * @author Alain Pitiot
    + * @version 2022.2.3
    + * @copyright (c) 2022 Open Science Tools Ltd. (https://opensciencetools.org)
      * @license Distributed under the terms of the MIT License
      */
     
    @@ -41,13 +13,17 @@ import {PsychoJS} from "../core/PsychoJS";
     
     
     /**
    - * Transcript returned by the transcriber
    - *
    - * @name module:sound.Transcript
    - * @class
    + * Transcript.
      */
     export class Transcript
     {
    +	/**
    +	 * Object holding a transcription result.
    +	 *
    +	 * @param {SpeechRecognition} transcriber - the transcriber
    +	 * @param {string} text - the transcript
    +	 * @param {number} confidence - confidence in the transcript
    +	 */
     	constructor(transcriber, text = '', confidence = 0.0)
     	{
     		// recognised text:
    @@ -69,32 +45,36 @@ export class Transcript
     
     
     /**
    - * <p>This manager handles the transcription of speech into text.</p>
    - *
    - * @name module:sound.Transcriber
    - * @class
    - * @param {Object} options
    - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
    - * @param {String} options.name - the name used when logging messages
    - * @param {number} [options.bufferSize= 10000] - the maximum size of the circular transcript buffer
    - * @param {String[]} [options.continuous= true] - whether or not to continuously recognise
    - * @param {String[]} [options.lang= 'en-US'] - the spoken language
    - * @param {String[]} [options.interimResults= false] - whether or not to make interim results available
    - * @param {String[]} [options.maxAlternatives= 1] - the maximum number of recognition alternatives
    - * @param {String[]} [options.tokens= [] ] - the tokens to be recognised. This is experimental technology, not available in all browser.
    - * @param {Clock} [options.clock= undefined] - an optional clock
    - * @param {boolean} [options.autoLog= false] - whether or not to log
    + * 

    This manager handles the live transcription of speech into text.

    * + * @extends PsychObject * @todo deal with alternatives, interim results, and recognition errors */ -export class Transcriber extends PsychObject +export class SpeechRecognition extends PsychObject { - + /** + *

    This manager handles the live transcription of speech into text.

    + * + * @memberOf module:sound + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {String} options.name - the name used when logging messages + * @param {number} [options.bufferSize= 10000] - the maximum size of the circular transcript buffer + * @param {String[]} [options.continuous= true] - whether to continuously recognise + * @param {String[]} [options.lang= 'en-US'] - the spoken language + * @param {String[]} [options.interimResults= false] - whether to make interim results available + * @param {String[]} [options.maxAlternatives= 1] - the maximum number of recognition alternatives + * @param {String[]} [options.tokens= [] ] - the tokens to be recognised. This is experimental technology, not available in all browser. + * @param {Clock} [options.clock= undefined] - an optional clock + * @param {boolean} [options.autoLog= false] - whether to log + * + * @todo deal with alternatives, interim results, and recognition errors + */ constructor({psychoJS, name, bufferSize, continuous, lang, interimResults, maxAlternatives, tokens, clock, autoLog} = {}) { super(psychoJS); - this._addAttribute('name', name, 'transcriber'); + this._addAttribute('name', name, 'speech recognition'); this._addAttribute('bufferSize', bufferSize, 10000); this._addAttribute('continuous', continuous, true, this._onChange); this._addAttribute('lang', lang, 'en-US', this._onChange); @@ -105,8 +85,7 @@ export class Transcriber extends PsychObject this._addAttribute('autoLog', false, autoLog); this._addAttribute('status', PsychoJS.Status.NOT_STARTED); - // prepare the transcription: - this._prepareTranscription(); + this._prepareRecognition(); if (this._autoLog) { @@ -116,18 +95,15 @@ export class Transcriber extends PsychObject /** - * Start the transcription. + * Start the speech recognition process. * - * @name module:sound.Transcriber#start - * @function - * @public - * @return {Promise} promise fulfilled when the transcription actually started + * @return {Promise} promise fulfilled when the process actually starts */ start() { if (this._status !== PsychoJS.Status.STARTED) { - this._psychoJS.logger.debug('request to start speech to text transcription'); + this._psychoJS.logger.debug('request to start the speech recognition process'); try { @@ -138,7 +114,7 @@ export class Transcriber extends PsychObject this._recognition.start(); - // return a promise, which will be satisfied when the transcription actually starts, + // return a promise, which will be satisfied when the process actually starts, // which is also when the reset of the clock and the change of status takes place const self = this; return new Promise((resolve, reject) => @@ -167,22 +143,19 @@ export class Transcriber extends PsychObject /** - * Stop the transcription. + * Stop the speech recognition process. * - * @name module:sound.Transcriber#stop - * @function - * @public - * @return {Promise} promise fulfilled when the speech recognition actually stopped + * @return {Promise} promise fulfilled when the process actually stops */ stop() { if (this._status === PsychoJS.Status.STARTED) { - this._psychoJS.logger.debug('request to stop speech to text transcription'); + this._psychoJS.logger.debug('request to stop the speech recognition process'); this._recognition.stop(); - // return a promise, which will be satisfied when the recognition actually stops: + // return a promise, which will be satisfied when the process actually stops: const self = this; return new Promise((resolve, reject) => { @@ -197,9 +170,6 @@ export class Transcriber extends PsychObject * Get the list of transcripts still in the buffer, i.e. those that have not been * previously cleared by calls to getTranscripts with clear = true. * - * @name module:sound.Transcriber#getTranscripts - * @function - * @public * @param {Object} options * @param {string[]} [options.transcriptList= []]] - the list of transcripts texts to consider. If transcriptList is empty, we consider all transcripts. * @param {boolean} [options.clear= false] - whether or not to keep in the buffer the transcripts for a subsequent call to getTranscripts. If a keyList has been given and clear = true, we only remove from the buffer those keys in keyList @@ -216,7 +186,6 @@ export class Transcriber extends PsychObject return []; } - // iterate over the buffer, from start to end, and discard the null transcripts (i.e. those // previously cleared): const filteredTranscripts = []; @@ -248,9 +217,6 @@ export class Transcriber extends PsychObject /** * Clear all transcripts and resets the circular buffers. - * - * @name module:sound.Transcriber#clearTranscripts - * @function */ clearTranscripts() { @@ -264,10 +230,9 @@ export class Transcriber extends PsychObject /** * Callback for changes to the recognition settings. * - * <p>Changes to the recognition settings require the recognition to stop and be re-started.</p> + *

    Changes to the recognition settings require the speech recognition process + * to be stopped and be re-started.

    * - * @name module:sound.Transcriber#_onChange - * @function * @protected */ _onChange() @@ -277,25 +242,22 @@ export class Transcriber extends PsychObject this.stop(); } - this._prepareTranscription(); + this._prepareRecognition(); this.start(); } /** - * Prepare the transcription. + * Prepare the speech recognition process. * - * @name module:sound.Transcriber#_prepareTranscription - * @function * @protected */ - _prepareTranscription() + _prepareRecognition() { // setup the circular buffer of transcripts: this.clearTranscripts(); - // recognition settings: const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; this._recognition = new SpeechRecognition(); @@ -305,20 +267,19 @@ export class Transcriber extends PsychObject this._recognition.maxAlternatives = this._maxAlternatives; // grammar list with tokens added: - if (Array.isArray(this._tokens) && this._tokens.length > 0) + if (Array.isArray(this._tokens) && this._tokens.length > 0) { const SpeechGrammarList = window.SpeechGrammarList || window.webkitSpeechGrammarList; // note: we accepts JSGF encoded strings, and relative weight indicator between 0.0 and 1.0 // ref: https://www.w3.org/TR/jsgf/ - const name = 'NULL'; - const grammar = `#JSGF V1.0; grammar ${name}; public <${name}> = ${this._tokens.join('|')};` + const name = "NULL"; + const grammar = `#JSGF V1.0; grammar ${name}; public <${name}> = ${this._tokens.join('|')};` const grammarList = new SpeechGrammarList(); grammarList.addFromString(grammar, 1); this._recognition.grammars = grammarList; } - // setup the callbacks: const self = this; @@ -344,7 +305,7 @@ export class Transcriber extends PsychObject this._status = PsychoJS.Status.STARTED; self._psychoJS.logger.debug('speech recognition started'); - // resolve the Transcriber.start promise, if need be: + // resolve the SpeechRecognition.start promise, if need be: if (self._startCallback()) { self._startCallback({ @@ -359,7 +320,7 @@ export class Transcriber extends PsychObject this._status = PsychoJS.Status.STOPPED; self._psychoJS.logger.debug('speech recognition ended'); - // resolve the Transcriber.stop promise, if need be: + // resolve the SpeechRecognition.stop promise, if need be: if (self._stopCallback) { self._stopCallback({ @@ -413,32 +374,8 @@ export class Transcriber extends PsychObject self._psychoJS.logger.error('speech recognition error: ', JSON.stringify(event)); self._status = PsychoJS.Status.ERROR; } - } } -
    -
    -
    - - - - -
    - - - -
    - -
    - Documentation generated by JSDoc 3.6.7 on Thu Jun 16 2022 12:47:14 GMT+0200 (Central European Summer Time) -
    - - - - - diff --git a/src/sound/TonePlayer.js b/src/sound/TonePlayer.js index a552162..488016a 100644 --- a/src/sound/TonePlayer.js +++ b/src/sound/TonePlayer.js @@ -2,8 +2,8 @@ * Tone Player. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -14,18 +14,21 @@ import { SoundPlayer } from "./SoundPlayer.js"; /** *

    This class handles the playing of tones.

    * - * @name module:sound.TonePlayer - * @class * @extends SoundPlayer - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {number} [options.duration_s= 0.5] - duration of the tone (in seconds). If duration_s == -1, the sound will play indefinitely. - * @param {string|number} [options.note= 'C4'] - note (if string) or frequency (if number) - * @param {number} [options.volume= 1.0] - volume of the tone (must be between 0 and 1.0) - * @param {number} [options.loops= 0] - how many times to repeat the tone after it has played once. If loops == -1, the tone will repeat indefinitely until stopped. */ export class TonePlayer extends SoundPlayer { + /** + *

    This class handles the playing of tones.

    + * + * @memberOf module:sound + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {number} [options.duration_s= 0.5] - duration of the tone (in seconds). If duration_s == -1, the sound will play indefinitely. + * @param {string|number} [options.note= 'C4'] - note (if string) or frequency (if number) + * @param {number} [options.volume= 1.0] - volume of the tone (must be between 0 and 1.0) + * @param {number} [options.loops= 0] - how many times to repeat the tone after it has played once. If loops == -1, the tone will repeat indefinitely until stopped. + */ constructor({ psychoJS, note = "C4", @@ -63,10 +66,6 @@ export class TonePlayer extends SoundPlayer *

    Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, * we throw an exception.

    * - * @name module:sound.TonePlayer.accept - * @function - * @static - * @public * @param {module:sound.Sound} sound - the sound * @return {Object|undefined} an instance of TonePlayer that can play the given sound or undefined otherwise */ @@ -117,9 +116,6 @@ export class TonePlayer extends SoundPlayer /** * Get the duration of the sound. * - * @name module:sound.TonePlayer#getDuration - * @function - * @public * @return {number} the duration of the sound, in seconds */ getDuration() @@ -130,9 +126,6 @@ export class TonePlayer extends SoundPlayer /** * Set the duration of the tone. * - * @name module:sound.TonePlayer#setDuration - * @function - * @public * @param {number} duration_s - the duration of the tone (in seconds) If duration_s == -1, the sound will play indefinitely. */ setDuration(duration_s) @@ -143,9 +136,6 @@ export class TonePlayer extends SoundPlayer /** * Set the number of loops. * - * @name module:sound.TonePlayer#setLoops - * @function - * @public * @param {number} loops - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped. */ setLoops(loops) @@ -156,9 +146,6 @@ export class TonePlayer extends SoundPlayer /** * Set the volume of the tone. * - * @name module:sound.TonePlayer#setVolume - * @function - * @public * @param {Integer} volume - the volume of the tone * @param {boolean} [mute= false] - whether or not to mute the tone */ @@ -188,9 +175,6 @@ export class TonePlayer extends SoundPlayer /** * Start playing the sound. * - * @name module:sound.TonePlayer#play - * @function - * @public * @param {boolean} [loops] - how many times to repeat the sound after it has played once. If loops == -1, the sound will repeat indefinitely until stopped. */ play(loops) @@ -254,10 +238,6 @@ export class TonePlayer extends SoundPlayer /** * Stop playing the sound immediately. - * - * @name module:sound.TonePlayer#stop - * @function - * @public */ stop() { @@ -285,8 +265,6 @@ export class TonePlayer extends SoundPlayer *

    Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11, * we throw an exception.

    * - * @name module:sound.TonePlayer._initSoundLibrary - * @function * @protected */ _initSoundLibrary() diff --git a/src/sound/TrackPlayer.js b/src/sound/TrackPlayer.js index a5dcbda..7451ae6 100644 --- a/src/sound/TrackPlayer.js +++ b/src/sound/TrackPlayer.js @@ -2,8 +2,8 @@ * Track Player. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ @@ -12,22 +12,23 @@ import { SoundPlayer } from "./SoundPlayer.js"; /** *

    This class handles the playback of sound tracks.

    * - * @name module:sound.TrackPlayer - * @class * @extends SoundPlayer - * @param {Object} options - * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance - * @param {Object} options.howl - the sound object (see {@link https://howlerjs.com/}) - * @param {number} [options.startTime= 0] - start of playback (in seconds) - * @param {number} [options.stopTime= -1] - end of playback (in seconds) - * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo - * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) - * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played * * @todo stopTime is currently not implemented (tracks will play from startTime to finish) * @todo stereo is currently not implemented */ export class TrackPlayer extends SoundPlayer { + /** + * @memberOf module:sound + * @param {Object} options + * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance + * @param {Object} options.howl - the sound object (see {@link https://howlerjs.com/}) + * @param {number} [options.startTime= 0] - start of playback (in seconds) + * @param {number} [options.stopTime= -1] - end of playback (in seconds) + * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo + * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0) + * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played + */ constructor({ psychoJS, howl, @@ -53,10 +54,6 @@ export class TrackPlayer extends SoundPlayer /** * Determine whether this player can play the given sound. * - * @name module:sound.TrackPlayer.accept - * @function - * @static - * @public * @param {module:sound.Sound} sound - the sound, which should be the name of an audio resource * file * @return {Object|undefined} an instance of TrackPlayer that can play the given track or undefined otherwise @@ -90,9 +87,6 @@ export class TrackPlayer extends SoundPlayer /** * Get the duration of the sound, in seconds. * - * @name module:sound.TrackPlayer#getDuration - * @function - * @public * @return {number} the duration of the track, in seconds */ getDuration() @@ -103,9 +97,6 @@ export class TrackPlayer extends SoundPlayer /** * Set the duration of the track. * - * @name module:sound.TrackPlayer#setDuration - * @function - * @public * @param {number} duration_s - the duration of the track in seconds */ setDuration(duration_s) @@ -120,9 +111,6 @@ export class TrackPlayer extends SoundPlayer /** * Set the volume of the tone. * - * @name module:sound.TrackPlayer#setVolume - * @function - * @public * @param {Integer} volume - the volume of the track (must be between 0 and 1.0) * @param {boolean} [mute= false] - whether or not to mute the track */ @@ -137,9 +125,6 @@ export class TrackPlayer extends SoundPlayer /** * Set the number of loops. * - * @name module:sound.TrackPlayer#setLoops - * @function - * @public * @param {number} loops - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped. */ setLoops(loops) @@ -160,9 +145,6 @@ export class TrackPlayer extends SoundPlayer /** * Start playing the sound. * - * @name module:sound.TrackPlayer#play - * @function - * @public * @param {number} loops - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped. * @param {number} [fadeDuration = 17] - how long should the fading in last in ms */ @@ -201,9 +183,6 @@ export class TrackPlayer extends SoundPlayer /** * Stop playing the sound immediately. * - * @name module:sound.TrackPlayer#stop - * @function - * @public * @param {number} [fadeDuration = 17] - how long should the fading out last in ms */ stop(fadeDuration = 17) diff --git a/src/sound/index.js b/src/sound/index.js index 81637d7..979ef53 100644 --- a/src/sound/index.js +++ b/src/sound/index.js @@ -2,8 +2,7 @@ export * from "./Sound.js"; export * from "./SoundPlayer.js"; export * from "./TonePlayer.js"; export * from "./TrackPlayer.js"; - export * from "./AudioClip.js"; export * from "./AudioClipPlayer.js"; export * from "./Microphone.js"; -// export * from './Transcriber.js'; +export * from './SpeechRecognition.js'; diff --git a/src/util/Clock.js b/src/util/Clock.js index 5259a46..cd89800 100644 --- a/src/util/Clock.js +++ b/src/util/Clock.js @@ -2,20 +2,20 @@ * Clock component. * * @author Alain Pitiot - * @version 2021.2.0 - * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org) + * @version 2022.2.3 + * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org) * @license Distributed under the terms of the MIT License */ /** *

    MonotonicClock offers a convenient way to keep track of time during experiments. An experiment can have as many independent clocks as needed, e.g. one to time responses, another one to keep track of stimuli, etc.

    - * - * @name module:util.MonotonicClock - * @class - * @param {number} [startTime=