An easy-to-use platform for EEG experimentation in the classroom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Ran lint-fix

+452 -447
+1 -1
app/actions/deviceActions.ts
··· 33 33 SetSignalQualityObservable: createAction<any, 'SET_SIGNAL_OBSERVABLE'>( 34 34 'SET_SIGNAL_OBSERVABLE' 35 35 ), 36 - Cleanup: createAction<any, 'CLEANUP'>('CLEANUP') 36 + Cleanup: createAction<any, 'CLEANUP'>('CLEANUP'), 37 37 } as const; 38 38 39 39 export type DeviceActionType = ActionType<
+1 -1
app/actions/experimentActions.ts
··· 29 29 SaveWorkspace: createAction('SAVE_WORKSPACE'), 30 30 SetState: createAction<any, 'SET_EXPERIMENT_STATE'>('SET_EXPERIMENT_STATE'), 31 31 SetEEGEnabled: createAction<any, 'SET_EEG_ENABLED'>('SET_EEG_ENABLED'), 32 - UpdateSession: createAction('UPDATE_SESSION') 32 + UpdateSession: createAction('UPDATE_SESSION'), 33 33 } as const; 34 34 35 35 export type ExperimentActionType = ActionType<
+1 -1
app/actions/jupyterActions.ts
··· 42 42 ReceiveDisplayData: createAction<any, 'RECEIVE_DISPLAY_DATA'>( 43 43 'RECEIVE_DISPLAY_DATA' 44 44 ), 45 - ReceiveStream: createAction<any, 'RECEIVE_STREAM'>('RECEIVE_STREAM') 45 + ReceiveStream: createAction<any, 'RECEIVE_STREAM'>('RECEIVE_STREAM'), 46 46 } as const; 47 47 48 48 export type JupyterActionType = ActionType<
+27 -27
app/components/AnalyzeComponent.tsx
··· 8 8 Divider, 9 9 Button, 10 10 Checkbox, 11 - Sidebar 11 + Sidebar, 12 12 } from 'semantic-ui-react'; 13 13 import { isNil } from 'lodash'; 14 14 import Plot from 'react-plotly.js'; ··· 18 18 MUSE_CHANNELS, 19 19 EMOTIV_CHANNELS, 20 20 KERNEL_STATUS, 21 - EXPERIMENTS 21 + EXPERIMENTS, 22 22 } from '../constants/constants'; 23 23 import { 24 24 readWorkspaceCleanedEEGData, 25 25 getSubjectNamesFromFiles, 26 26 readWorkspaceBehaviorData, 27 27 readBehaviorData, 28 - storeAggregatedBehaviorData 28 + storeAggregatedBehaviorData, 29 29 } from '../utils/filesystem/storage'; 30 30 import { 31 31 aggregateDataForPlot, 32 - aggregateBehaviorDataToSave 32 + aggregateBehaviorDataToSave, 33 33 } from '../utils/behavior/compute'; 34 34 import SecondaryNavComponent from './SecondaryNavComponent'; 35 35 import ClickableHeadDiagramSVG from './svgs/ClickableHeadDiagramSVG'; ··· 41 41 const ANALYZE_STEPS = { 42 42 OVERVIEW: 'OVERVIEW', 43 43 ERP: 'ERP', 44 - BEHAVIOR: 'BEHAVIOR' 44 + BEHAVIOR: 'BEHAVIOR', 45 45 }; 46 46 47 47 const ANALYZE_STEPS_BEHAVIOR = { 48 - BEHAVIOR: 'BEHAVIOR' 48 + BEHAVIOR: 'BEHAVIOR', 49 49 }; 50 50 51 51 interface Props { ··· 161 161 selectedChannel: 162 162 props.deviceType === DEVICES.EMOTIV 163 163 ? EMOTIV_CHANNELS[0] 164 - : MUSE_CHANNELS[0] 164 + : MUSE_CHANNELS[0], 165 165 }; 166 166 this.handleChannelSelect = this.handleChannelSelect.bind(this); 167 167 this.handleDatasetChange = this.handleDatasetChange.bind(this); ··· 191 191 } 192 192 const behavioralData = await readWorkspaceBehaviorData(this.props.title); 193 193 this.setState({ 194 - eegFilePaths: workspaceCleanData.map(filepath => ({ 194 + eegFilePaths: workspaceCleanData.map((filepath) => ({ 195 195 key: filepath.name, 196 196 text: filepath.name, 197 - value: filepath.path 197 + value: filepath.path, 198 198 })), 199 - behaviorFilePaths: behavioralData.map(filepath => ({ 199 + behaviorFilePaths: behavioralData.map((filepath) => ({ 200 200 key: filepath.name, 201 201 text: filepath.name, 202 - value: filepath.path 202 + value: filepath.path, 203 203 })), 204 - dependentVariables: ['Response Time', 'Accuracy'].map(dv => ({ 204 + dependentVariables: ['Response Time', 'Accuracy'].map((dv) => ({ 205 205 key: dv, 206 206 text: dv, 207 - value: dv 207 + value: dv, 208 208 })), 209 - selectedDependentVariable: 'Response Time' 209 + selectedDependentVariable: 'Response Time', 210 210 }); 211 211 } 212 212 ··· 220 220 handleDatasetChange(event: object, data: object) { 221 221 this.setState({ 222 222 selectedFilePaths: data.value, 223 - selectedSubjects: getSubjectNamesFromFiles(data.value) 223 + selectedSubjects: getSubjectNamesFromFiles(data.value), 224 224 }); 225 225 this.props.JupyterActions.LoadCleanedEpochs(data.value); 226 226 } ··· 237 237 selectedBehaviorFilePaths: data.value, 238 238 selectedSubjects: getSubjectNamesFromFiles(data.value), 239 239 dataToPlot, 240 - layout 240 + layout, 241 241 }); 242 242 } 243 243 ··· 245 245 const behavioralData = await readWorkspaceBehaviorData(this.props.title); 246 246 if (behavioralData.length !== this.state.behaviorFilePaths.length) { 247 247 this.setState({ 248 - behaviorFilePaths: behavioralData.map(filepath => ({ 248 + behaviorFilePaths: behavioralData.map((filepath) => ({ 249 249 key: filepath.name, 250 250 text: filepath.name, 251 - value: filepath.path 252 - })) 251 + value: filepath.path, 252 + })), 253 253 }); 254 254 } 255 255 } ··· 265 265 this.setState({ 266 266 selectedDependentVariable: data.value, 267 267 dataToPlot, 268 - layout 268 + layout, 269 269 }); 270 270 } 271 271 ··· 281 281 removeOutliers: !this.state.removeOutliers, 282 282 dataToPlot, 283 283 layout, 284 - helpMode: 'outliers' 284 + helpMode: 'outliers', 285 285 }); 286 286 } 287 287 ··· 296 296 this.setState({ 297 297 showDataPoints: !this.state.showDataPoints, 298 298 dataToPlot, 299 - layout 299 + layout, 300 300 }); 301 301 } 302 302 ··· 316 316 dataToPlot, 317 317 layout, 318 318 displayMode, 319 - helpMode: displayMode 319 + helpMode: displayMode, 320 320 }); 321 321 } 322 322 } 323 323 324 324 toggleDisplayInfoVisibility() { 325 325 this.setState({ 326 - isSidebarVisible: !this.state.isSidebarVisible 326 + isSidebarVisible: !this.state.isSidebarVisible, 327 327 }); 328 328 } 329 329 ··· 351 351 this.state.selectedFilePaths.length >= 1 352 352 ) { 353 353 const numberConditions = this.props.epochsInfo.filter( 354 - infoObj => 354 + (infoObj) => 355 355 infoObj.name !== 'Drop Percentage' && infoObj.name !== 'Total Epochs' 356 356 ).length; 357 357 let colors; ··· 364 364 <div> 365 365 {this.props.epochsInfo 366 366 .filter( 367 - infoObj => 367 + (infoObj) => 368 368 infoObj.name !== 'Drop Percentage' && 369 369 infoObj.name !== 'Total Epochs' 370 370 ) ··· 566 566 overflow: 'auto', 567 567 maxHeight: 650, 568 568 display: 'grid', 569 - justifyContent: 'center' 569 + justifyContent: 'center', 570 570 }} 571 571 > 572 572 <Segment basic textAlign="left" className={styles.plotSegment}>
+2 -2
app/components/CleanComponent/CleanSidebar.tsx
··· 11 11 LEARN_BRAIN = 5, 12 12 LEARN_BLINK = 6, 13 13 LEARN_THOUGHT = 7, 14 - LEARN_ALPHA = 8 14 + LEARN_ALPHA = 8, 15 15 } 16 16 17 17 interface Props { ··· 25 25 constructor(props) { 26 26 super(props); 27 27 this.state = { 28 - helpStep: HELP_STEP.MENU 28 + helpStep: HELP_STEP.MENU, 29 29 }; 30 30 this.handleStartLearn = this.handleStartLearn.bind(this); 31 31 this.handleStartSignal = this.handleStartSignal.bind(this);
+10 -10
app/components/CleanComponent/index.tsx
··· 11 11 Divider, 12 12 DropdownProps, 13 13 DropdownItemProps, 14 - SemanticICONS 14 + SemanticICONS, 15 15 } from 'semantic-ui-react'; 16 16 import * as path from 'path'; 17 17 import { Link } from 'react-router-dom'; ··· 58 58 eegFilePaths: [{ key: '', text: '', value: '' }], 59 59 selectedFilePaths: [], 60 60 selectedSubject: props.subject, 61 - isSidebarVisible: false 61 + isSidebarVisible: false, 62 62 }; 63 63 this.handleRecordingChange = this.handleRecordingChange.bind(this); 64 64 this.handleLoadData = this.handleLoadData.bind(this); ··· 78 78 this.setState({ 79 79 subjects: workspaceRawData 80 80 .map( 81 - filepath => 81 + (filepath) => 82 82 filepath.path.split(path.sep)[ 83 83 filepath.path.split(path.sep).length - 3 84 84 ] 85 85 ) 86 86 .reduce((acc, curr) => { 87 - if (acc.find(subject => subject.key === curr)) { 87 + if (acc.find((subject) => subject.key === curr)) { 88 88 return acc; 89 89 } 90 90 return acc.concat({ 91 91 key: curr, 92 92 text: curr, 93 - value: curr 93 + value: curr, 94 94 }); 95 95 }, []), 96 - eegFilePaths: workspaceRawData.map(filepath => ({ 96 + eegFilePaths: workspaceRawData.map((filepath) => ({ 97 97 key: filepath.name, 98 98 text: filepath.name, 99 - value: filepath.path 100 - })) 99 + value: filepath.path, 100 + })), 101 101 }); 102 102 } 103 103 ··· 147 147 const { epochsInfo } = this.props; 148 148 if (!isNil(epochsInfo)) { 149 149 const drop = epochsInfo.find( 150 - infoObj => infoObj.name === 'Drop Percentage' 150 + (infoObj) => infoObj.name === 'Drop Percentage' 151 151 )?.value; 152 152 153 153 if (drop && drop >= 2) { ··· 214 214 selection 215 215 closeOnChange 216 216 value={this.state.selectedFilePaths} 217 - options={this.state.eegFilePaths.filter(filepath => { 217 + options={this.state.eegFilePaths.filter((filepath) => { 218 218 if (isString(filepath.value)) { 219 219 const subjectFromFilepath = filepath.value.split( 220 220 path.sep
+6 -6
app/components/CollectComponent/ConnectModal.tsx
··· 6 6 DEVICES, 7 7 DEVICE_AVAILABILITY, 8 8 CONNECTION_STATUS, 9 - SCREENS 9 + SCREENS, 10 10 } from '../../constants/constants'; 11 11 import styles from '../styles/collect.css'; 12 12 import { SignalQualityData } from '../../constants/interfaces'; ··· 33 33 enum INSTRUCTION_PROGRESS { 34 34 SEARCHING, 35 35 TURN_ON, 36 - COMPUTER_CONNECTABILITY 36 + COMPUTER_CONNECTABILITY, 37 37 } 38 38 39 39 export default class ConnectModal extends Component<Props, State> { ··· 51 51 super(props); 52 52 this.state = { 53 53 selectedDevice: null, 54 - instructionProgress: INSTRUCTION_PROGRESS.SEARCHING 54 + instructionProgress: INSTRUCTION_PROGRESS.SEARCHING, 55 55 }; 56 56 this.handleSearch = debounce(this.handleSearch.bind(this), 300, { 57 57 leading: true, 58 - trailing: false 58 + trailing: false, 59 59 }); 60 60 this.handleConnect = debounce(this.handleConnect.bind(this), 1000, { 61 61 leading: true, 62 - trailing: false 62 + trailing: false, 63 63 }); 64 64 this.handleinstructionProgress = this.handleinstructionProgress.bind(this); 65 65 } ··· 100 100 return ( 101 101 <Segment basic> 102 102 <List divided relaxed inverted> 103 - {this.props.availableDevices.map(device => ( 103 + {this.props.availableDevices.map((device) => ( 104 104 <List.Item className={styles.deviceItem} key={device.id}> 105 105 <List.Icon 106 106 link
+6 -6
app/components/CollectComponent/HelpSidebar.tsx
··· 12 12 LEARN_BRAIN, 13 13 LEARN_BLINK, 14 14 LEARN_THOUGHTS, 15 - LEARN_ALPHA 15 + LEARN_ALPHA, 16 16 } 17 17 18 18 interface Props { ··· 30 30 constructor(props) { 31 31 super(props); 32 32 this.state = { 33 - helpStep: HELP_STEP.MENU 33 + helpStep: HELP_STEP.MENU, 34 34 }; 35 35 this.handleStartLearn = this.handleStartLearn.bind(this); 36 36 this.handleStartSignal = this.handleStartSignal.bind(this); ··· 53 53 ) { 54 54 this.setState({ helpStep: HELP_STEP.MENU }); 55 55 } else { 56 - this.setState(prevState => ({ 56 + this.setState((prevState) => ({ 57 57 ...prevState, 58 - helpStep: prevState.helpStep + 1 58 + helpStep: prevState.helpStep + 1, 59 59 })); 60 60 } 61 61 } 62 62 63 63 handleBack() { 64 - this.setState(prevState => ({ 64 + this.setState((prevState) => ({ 65 65 ...prevState, 66 - helpStep: prevState.helpStep - 1 66 + helpStep: prevState.helpStep - 1, 67 67 })); 68 68 } 69 69
+9 -9
app/components/CollectComponent/PreTestComponent.tsx
··· 5 5 Button, 6 6 List, 7 7 Header, 8 - Sidebar 8 + Sidebar, 9 9 } from 'semantic-ui-react'; 10 10 import Mousetrap from 'mousetrap'; 11 11 import ViewerComponent from '../ViewerComponent'; ··· 21 21 DEVICE_AVAILABILITY, 22 22 EXPERIMENTS, 23 23 PLOTTING_INTERVAL, 24 - CONNECTION_STATUS 24 + CONNECTION_STATUS, 25 25 } from '../../constants/constants'; 26 26 import { 27 27 ExperimentParameters, 28 28 MainTimeline, 29 - Trial 29 + Trial, 30 30 } from '../../constants/interfaces'; 31 31 32 32 interface Props { ··· 67 67 super(props); 68 68 this.state = { 69 69 isPreviewing: false, 70 - isSidebarVisible: true 70 + isSidebarVisible: true, 71 71 }; 72 72 this.handlePreview = this.handlePreview.bind(this); 73 73 this.handleSidebarToggle = this.handleSidebarToggle.bind(this); ··· 88 88 89 89 handlePreview(e) { 90 90 e.target.blur(); 91 - this.setState(prevState => ({ 91 + this.setState((prevState) => ({ 92 92 ...prevState, 93 93 isSidebarVisible: false, 94 - isPreviewing: !prevState.isPreviewing 94 + isPreviewing: !prevState.isPreviewing, 95 95 })); 96 96 } 97 97 98 98 handleSidebarToggle() { 99 - this.setState(prevState => ({ 99 + this.setState((prevState) => ({ 100 100 ...prevState, 101 - isSidebarVisible: !prevState.isSidebarVisible 101 + isSidebarVisible: !prevState.isSidebarVisible, 102 102 })); 103 103 } 104 104 ··· 179 179 <Grid.Column floated="right"> 180 180 <PreviewButton 181 181 isPreviewing={this.state.isPreviewing} 182 - onClick={e => this.handlePreview(e)} 182 + onClick={(e) => this.handlePreview(e)} 183 183 /> 184 184 <Button 185 185 primary
+6 -6
app/components/CollectComponent/RunComponent.tsx
··· 12 12 import { 13 13 MainTimeline, 14 14 Trial, 15 - ExperimentParameters 15 + ExperimentParameters, 16 16 } from '../../constants/interfaces'; 17 17 import { ExperimentActions } from '../../actions'; 18 18 ··· 48 48 constructor(props: Props) { 49 49 super(props); 50 50 this.state = { 51 - isInputCollectOpen: props.subject.length === 0 51 + isInputCollectOpen: props.subject.length === 0, 52 52 }; 53 53 this.handleStartExperiment = this.handleStartExperiment.bind(this); 54 54 this.insertLabJsCallback = this.insertLabJsCallback.bind(this); ··· 69 69 const options = { 70 70 buttons: ['No', 'Yes'], 71 71 message: 72 - 'You already have a file with the same name. If you continue the experiment, the current file will be deleted. Do you really want to overwrite the data?' 72 + 'You already have a file with the same name. If you continue the experiment, the current file will be deleted. Do you really want to overwrite the data?', 73 73 }; 74 74 const response = await dialog.showMessageBox(options); 75 75 if (response.response === 1) { ··· 171 171 script: this.props.paradigm, 172 172 params: this.props.params, 173 173 eventCallback: this.insertLabJsCallback(), 174 - on_finish: csv => { 174 + on_finish: (csv) => { 175 175 this.props.ExperimentActions.Stop({ data: csv }); 176 - } 176 + }, 177 177 }} 178 178 /> 179 179 </div> ··· 199 199 data={{ 200 200 subject: this.props.subject, 201 201 group: this.props.group, 202 - session: this.props.session 202 + session: this.props.session, 203 203 }} 204 204 /> 205 205 </div>
+3 -3
app/components/CollectComponent/index.tsx
··· 5 5 EXPERIMENTS, 6 6 DEVICES, 7 7 CONNECTION_STATUS, 8 - DEVICE_AVAILABILITY 8 + DEVICE_AVAILABILITY, 9 9 } from '../../constants/constants'; 10 10 import { 11 11 MainTimeline, 12 12 Trial, 13 13 ExperimentParameters, 14 - SignalQualityData 14 + SignalQualityData, 15 15 } from '../../constants/interfaces'; 16 16 import PreTestComponent from './PreTestComponent'; 17 17 import ConnectModal from './ConnectModal'; ··· 57 57 super(props); 58 58 this.state = { 59 59 isConnectModalOpen: false, 60 - isRunComponentOpen: !props.isEEGEnabled 60 + isRunComponentOpen: !props.isEEGEnabled, 61 61 }; 62 62 this.handleStartConnect = this.handleStartConnect.bind(this); 63 63 this.handleConnectModalClose = this.handleConnectModalClose.bind(this);
+57 -56
app/components/DesignComponent/CustomDesignComponent.tsx
··· 7 7 Form, 8 8 Checkbox, 9 9 Image, 10 - Table 10 + Table, 11 11 } from 'semantic-ui-react'; 12 12 import { isNil } from 'lodash'; 13 13 import { HashHistory } from 'history'; ··· 19 19 Trial, 20 20 ExperimentParameters, 21 21 ExperimentDescription, 22 - StimuliDesc 22 + StimuliDesc, 23 23 } from '../../constants/interfaces'; 24 24 import SecondaryNavComponent from '../SecondaryNavComponent'; 25 25 import PreviewExperimentComponent from '../PreviewExperimentComponent'; ··· 40 40 TRIALS: 'TRIALS', 41 41 PARAMETERS: 'PARAMETERS', 42 42 INSTRUCTIONS: 'INSTRUCTIONS', 43 - PREVIEW: 'PREVIEW' 43 + PREVIEW: 'PREVIEW', 44 44 }; 45 45 46 46 const FIELDS = { ··· 48 48 HYPOTHESIS: 'Hypothesis', 49 49 METHODS: 'Methods', 50 50 INTRO: 'Experiment Instructions', 51 - HELP: 'Instructions for the task screen' 51 + HELP: 'Instructions for the task screen', 52 52 }; 53 53 54 54 interface Props { ··· 87 87 isPreviewing: true, 88 88 description: props.description, 89 89 params: props.params, 90 - saved: false 90 + saved: false, 91 91 }; 92 92 this.handleStepClick = this.handleStepClick.bind(this); 93 93 this.handleStartExperiment = this.handleStartExperiment.bind(this); ··· 112 112 113 113 handleProgressBar(event: object, data: object) { 114 114 this.setState({ 115 - params: { ...this.state.params, showProgessBar: data.checked } 115 + params: { ...this.state.params, showProgessBar: data.checked }, 116 116 }); 117 117 } 118 118 ··· 141 141 { name: 'stimulus1', number: 1 }, 142 142 { name: 'stimulus2', number: 2 }, 143 143 { name: 'stimulus3', number: 3 }, 144 - { name: 'stimulus4', number: 4 } 144 + { name: 'stimulus4', number: 4 }, 145 145 ]; 146 146 switch (this.state.activeStep) { 147 147 case CUSTOM_STEPS.OVERVIEW: ··· 173 173 this.setState({ 174 174 description: { 175 175 ...this.state.description, 176 - question: data.value 176 + question: data.value, 177 177 }, 178 - saved: false 178 + saved: false, 179 179 }) 180 180 } 181 181 /> ··· 200 200 this.setState({ 201 201 description: { 202 202 ...this.state.description, 203 - hypothesis: data.value 203 + hypothesis: data.value, 204 204 }, 205 - saved: false 205 + saved: false, 206 206 }) 207 207 } 208 208 /> ··· 227 227 this.setState({ 228 228 description: { 229 229 ...this.state.description, 230 - methods: data.value 230 + methods: data.value, 231 231 }, 232 - saved: false 232 + saved: false, 233 233 }) 234 234 } 235 235 /> ··· 272 272 {...this.state.params[name]} 273 273 numberImages={ 274 274 this.state.params.stimuli.filter( 275 - trial => trial.type === number 275 + (trial) => trial.type === number 276 276 ).length 277 277 } 278 278 onChange={async (key, data, changedName) => { ··· 281 281 ...this.state.params, 282 282 [changedName]: { 283 283 ...this.state.params[changedName], 284 - [key]: data 285 - } 286 - } 284 + [key]: data, 285 + }, 286 + }, 287 287 }); 288 288 let newStimuli: StimuliDesc[] = []; 289 - await stimi.forEach(stimul => { 289 + await stimi.forEach((stimul) => { 290 290 let dirStimuli: StimuliDesc[] = []; 291 291 const { dir } = this.state.params[stimul.name]; 292 292 if (dir && typeof dir !== 'undefined' && dir !== '') { 293 - dirStimuli = readImages(dir).map(i => ({ 293 + dirStimuli = readImages(dir).map((i) => ({ 294 294 dir, 295 295 filename: i, 296 296 name: i, 297 297 condition: this.state.params[stimul.name].title, 298 298 response: this.state.params[stimul.name].response, 299 299 phase: 'main', 300 - type: stimul.number 300 + type: stimul.number, 301 301 })); 302 302 } 303 303 if (dirStimuli.length) dirStimuli[0].phase = 'practice'; ··· 307 307 params: { 308 308 ...this.state.params, 309 309 stimuli: [...newStimuli], 310 - nbTrials: newStimuli.filter(t => t.phase === 'main') 310 + nbTrials: newStimuli.filter((t) => t.phase === 'main') 311 311 .length, 312 312 nbPracticeTrials: newStimuli.filter( 313 - t => t.phase === 'practice' 314 - ).length 313 + (t) => t.phase === 'practice' 314 + ).length, 315 315 }, 316 - saved: false 316 + saved: false, 317 317 }); 318 318 }} 319 319 /> ··· 348 348 this.setState({ 349 349 params: { 350 350 ...this.state.params, 351 - randomize: data.value 351 + randomize: data.value, 352 352 }, 353 - saved: false 353 + saved: false, 354 354 }); 355 355 } 356 356 }} ··· 360 360 { 361 361 key: 'sequential', 362 362 text: 'Sequential', 363 - value: 'sequential' 364 - } 363 + value: 'sequential', 364 + }, 365 365 ]} 366 366 /> 367 367 <Form.Input ··· 373 373 this.setState({ 374 374 params: { 375 375 ...this.state.params, 376 - nbTrials: parseInt(data.value, 10) 376 + nbTrials: parseInt(data.value, 10), 377 377 }, 378 - saved: false 378 + saved: false, 379 379 }) 380 380 } 381 381 /> ··· 388 388 this.setState({ 389 389 params: { 390 390 ...this.state.params, 391 - nbPracticeTrials: parseInt(data.value, 10) 391 + nbPracticeTrials: parseInt(data.value, 10), 392 392 }, 393 - saved: false 393 + saved: false, 394 394 }) 395 395 } 396 396 /> ··· 417 417 key={`stim_row_${num}`} 418 418 num={num} 419 419 conditions={[1, 2, 3, 4].map( 420 - n => this.state.params[`stimulus${n}`].title 420 + (n) => this.state.params[`stimulus${n}`].title 421 421 )} 422 422 {...e} 423 - onDelete={deletedNum => { 423 + onDelete={(deletedNum) => { 424 424 const { stimuli } = this.state.params; 425 425 stimuli.splice(deletedNum, 1); 426 426 const nbPracticeTrials = stimuli.filter( 427 - s => s.phase === 'practice' 427 + (s) => s.phase === 'practice' 428 428 ).length; 429 - const nbTrials = stimuli.filter(s => s.phase === 'main') 430 - .length; 429 + const nbTrials = stimuli.filter( 430 + (s) => s.phase === 'main' 431 + ).length; 431 432 this.setState({ 432 433 params: { 433 434 ...this.state.params, 434 435 stimuli: [...stimuli], 435 436 nbPracticeTrials, 436 - nbTrials 437 + nbTrials, 437 438 }, 438 - saved: false 439 + saved: false, 439 440 }); 440 441 }} 441 442 onChange={(changedNum, key, data) => { ··· 445 446 let { nbTrials } = this.state.params; 446 447 if (key === 'phase') { 447 448 nbPracticeTrials = stimuli.filter( 448 - s => s.phase === 'practice' 449 + (s) => s.phase === 'practice' 449 450 ).length; 450 - nbTrials = stimuli.filter(s => s.phase === 'main') 451 + nbTrials = stimuli.filter((s) => s.phase === 'main') 451 452 .length; 452 453 } 453 454 this.setState({ ··· 455 456 ...this.state.params, 456 457 stimuli: [...stimuli], 457 458 nbPracticeTrials, 458 - nbTrials 459 + nbTrials, 459 460 }, 460 - saved: false 461 + saved: false, 461 462 }); 462 463 }} 463 464 /> ··· 494 495 5: '1.25', 495 496 6: '1.5', 496 497 7: '1.75', 497 - 8: '2' 498 + 8: '2', 498 499 }} 499 500 msConversion="250" 500 - onChange={value => 501 + onChange={(value) => 501 502 this.setState({ 502 503 params: { ...this.state.params, iti: value }, 503 - saved: false 504 + saved: false, 504 505 }) 505 506 } 506 507 /> ··· 522 523 <Checkbox 523 524 defaultChecked={this.state.params.selfPaced} 524 525 label="Self-paced data collection" 525 - onChange={value => 526 + onChange={(value) => 526 527 this.setState({ 527 528 params: { 528 529 ...this.state.params, 529 - selfPaced: !this.state.params.selfPaced 530 + selfPaced: !this.state.params.selfPaced, 530 531 }, 531 - saved: false 532 + saved: false, 532 533 }) 533 534 } 534 535 /> ··· 551 552 5: '1.25', 552 553 6: '1.5', 553 554 7: '1.75', 554 - 8: '2' 555 + 8: '2', 555 556 }} 556 557 msConversion="250" 557 - onChange={value => 558 + onChange={(value) => 558 559 this.setState({ 559 560 params: { 560 561 ...this.state.params, 561 - presentationTime: value 562 + presentationTime: value, 562 563 }, 563 - saved: false 564 + saved: false, 564 565 }) 565 566 } 566 567 /> ··· 594 595 onChange={(event, data) => 595 596 this.setState({ 596 597 params: { ...this.state.params, intro: data.value }, 597 - saved: false 598 + saved: false, 598 599 }) 599 600 } 600 601 /> ··· 621 622 onChange={(event, data) => 622 623 this.setState({ 623 624 params: { ...this.state.params, taskHelp: data.value }, 624 - saved: false 625 + saved: false, 625 626 }) 626 627 } 627 628 /> ··· 656 657 <Segment basic> 657 658 <PreviewButton 658 659 isPreviewing={this.state.isPreviewing} 659 - onClick={e => this.handlePreview(e)} 660 + onClick={(e) => this.handlePreview(e)} 660 661 /> 661 662 </Segment> 662 663 </Grid.Column>
+2 -2
app/components/DesignComponent/ParamSlider.tsx
··· 16 16 msConversion, 17 17 value, 18 18 label, 19 - onChange 19 + onChange, 20 20 }) => { 21 21 return ( 22 22 <div> ··· 29 29 min={Math.min(...Object.keys(marks))} 30 30 max={Math.max(...Object.keys(marks))} 31 31 value={value / parseInt(msConversion, 10)} 32 - onChange={val => onChange(val * parseInt(msConversion, 10))} 32 + onChange={(val) => onChange(val * parseInt(msConversion, 10))} 33 33 defaultValue={1} 34 34 /> 35 35 ) : (
+5 -8
app/components/DesignComponent/StimuliDesignColumn.tsx
··· 20 20 const RESPONSE_OPTIONS = new Array(10).fill(0).map((_, i) => ({ 21 21 key: i.toString(), 22 22 text: i.toString(), 23 - value: i.toString() 23 + value: i.toString(), 24 24 })); 25 25 26 26 export default class StimuliDesignColumn extends Component<Props> { ··· 29 29 this.handleSelectFolder = this.handleSelectFolder.bind(this); 30 30 this.handleRemoveFolder = this.handleRemoveFolder.bind(this); 31 31 this.state = { 32 - numberImages: undefined 32 + numberImages: undefined, 33 33 }; 34 34 } 35 35 ··· 52 52 toast.error('No images in folder!'); 53 53 } 54 54 this.setState({ 55 - numberImages: images.length 55 + numberImages: images.length, 56 56 }); 57 57 this.props.onChange('dir', dir, `stimulus${this.props.num}`); 58 58 } ··· 60 60 61 61 handleRemoveFolder() { 62 62 this.setState({ 63 - numberImages: 0 63 + numberImages: 0, 64 64 }); 65 65 this.props.onChange('dir', '', `stimulus${this.props.num}`); 66 66 } ··· 108 108 <div> 109 109 Folder{' '} 110 110 {this.props.dir && 111 - this.props.dir 112 - .split(path.sep) 113 - .slice(-1) 114 - .join(' / ')} 111 + this.props.dir.split(path.sep).slice(-1).join(' / ')} 115 112 </div> 116 113 <div> 117 114 ( {this.state.numberImages || this.props.numberImages} images ){' '}
+4 -4
app/components/DesignComponent/StimuliRow.tsx
··· 18 18 const RESPONSE_OPTIONS = new Array(10).fill(0).map((_, i) => ({ 19 19 key: i.toString(), 20 20 text: i.toString(), 21 - value: i.toString() 21 + value: i.toString(), 22 22 })); 23 23 24 - export const StimuliRow: React.FC<Props> = props => { 24 + export const StimuliRow: React.FC<Props> = (props) => { 25 25 return ( 26 26 <Table.Row className={styles.trialsRow}> 27 27 <Table.Cell className={styles.conditionsNameRow}> ··· 51 51 <div 52 52 className={styles.trialsTrialTypeRowSelector} 53 53 style={{ 54 - backgroundColor: props.phase === 'main' ? '#1AC4EF' : '#EB1B66' 54 + backgroundColor: props.phase === 'main' ? '#1AC4EF' : '#EB1B66', 55 55 }} 56 56 > 57 57 {props.phase === 'main' ? 'Experimental' : 'Practice'} ··· 61 61 style={{ 62 62 display: 'grid', 63 63 color: '#C4C4C4', 64 - justifyContent: 'end' 64 + justifyContent: 'end', 65 65 }} 66 66 > 67 67 <Dropdown.Menu>
+9 -9
app/components/DesignComponent/index.tsx
··· 7 7 Header, 8 8 Image, 9 9 Checkbox, 10 - CheckboxProps 10 + CheckboxProps, 11 11 } from 'semantic-ui-react'; 12 12 import { isNil } from 'lodash'; 13 13 import { toast } from 'react-toastify'; ··· 19 19 MainTimeline, 20 20 Trial, 21 21 ExperimentParameters, 22 - ExperimentDescription 22 + ExperimentDescription, 23 23 } from '../../constants/interfaces'; 24 24 import SecondaryNavComponent from '../SecondaryNavComponent'; 25 25 import PreviewExperimentComponent from '../PreviewExperimentComponent'; ··· 50 50 OVERVIEW: 'OVERVIEW', 51 51 BACKGROUND: 'BACKGROUND', 52 52 PROTOCOL: 'PROTOCOL', 53 - PREVIEW: 'PREVIEW' 53 + PREVIEW: 'PREVIEW', 54 54 }; 55 55 56 56 export interface Props { ··· 104 104 activeStep: DESIGN_STEPS.OVERVIEW, 105 105 isPreviewing: false, 106 106 isNewExperimentModalOpen: false, 107 - recentWorkspaces: [] 107 + recentWorkspaces: [], 108 108 }; 109 109 this.handleStepClick = this.handleStepClick.bind(this); 110 110 this.handleStartExperiment = this.handleStartExperiment.bind(this); ··· 134 134 135 135 handleCustomizeExperiment() { 136 136 this.setState({ 137 - isNewExperimentModalOpen: true 137 + isNewExperimentModalOpen: true, 138 138 }); 139 139 } 140 140 ··· 152 152 this.props.ExperimentActions.CreateNewWorkspace({ 153 153 title, 154 154 type: EXPERIMENTS.CUSTOM, 155 - paradigm: 'Custom' 155 + paradigm: 'Custom', 156 156 // paradigm: this.props.paradigm 157 157 }); 158 158 this.props.ExperimentActions.SaveWorkspace(); ··· 160 160 161 161 handlePreview(e) { 162 162 e.target.blur(); 163 - this.setState(prevState => ({ 164 - isPreviewing: !prevState.isPreviewing 163 + this.setState((prevState) => ({ 164 + isPreviewing: !prevState.isPreviewing, 165 165 })); 166 166 } 167 167 ··· 280 280 <Grid.Column width={2}> 281 281 <Segment basic> 282 282 <div className={styles.externalLinks}> 283 - {this.props.background_links.map(link => ( 283 + {this.props.background_links.map((link) => ( 284 284 <Button 285 285 key={link.address} 286 286 secondary
+3 -3
app/components/EEGExplorationComponent.tsx
··· 5 5 Header, 6 6 Segment, 7 7 Image, 8 - Divider 8 + Divider, 9 9 } from 'semantic-ui-react'; 10 10 import { HashHistory } from 'history'; 11 11 import { 12 12 PLOTTING_INTERVAL, 13 13 CONNECTION_STATUS, 14 14 DEVICE_AVAILABILITY, 15 - DEVICES 15 + DEVICES, 16 16 } from '../constants/constants'; 17 17 import eegImage from '../assets/common/EEG.png'; 18 18 import SignalQualityIndicatorComponent from './SignalQualityIndicatorComponent'; ··· 42 42 constructor(props: Props) { 43 43 super(props); 44 44 this.state = { 45 - isConnectModalOpen: false 45 + isConnectModalOpen: false, 46 46 }; 47 47 this.handleConnectModalClose = this.handleConnectModalClose.bind(this); 48 48 this.handleStartConnect = this.handleStartConnect.bind(this);
+5 -5
app/components/HomeComponent/OverviewComponent.tsx
··· 11 11 const OVERVIEW_STEPS = { 12 12 OVERVIEW: 'OVERVIEW', 13 13 BACKGROUND: 'BACKGROUND', 14 - PROTOCOL: 'PROTOCOL' 14 + PROTOCOL: 'PROTOCOL', 15 15 }; 16 16 17 17 interface Props { ··· 30 30 super(props); 31 31 this.state = { 32 32 activeStep: OVERVIEW_STEPS.OVERVIEW, 33 - isPreviewing: false 33 + isPreviewing: false, 34 34 }; 35 35 this.handleStepClick = this.handleStepClick.bind(this); 36 36 this.handlePreview = this.handlePreview.bind(this); ··· 43 43 44 44 handlePreview(e) { 45 45 e.target.blur(); 46 - this.setState(prevState => ({ 46 + this.setState((prevState) => ({ 47 47 ...prevState, 48 - isPreviewing: !prevState.isPreviewing 48 + isPreviewing: !prevState.isPreviewing, 49 49 })); 50 50 } 51 51 ··· 79 79 </Segment> 80 80 <PreviewButton 81 81 isPreviewing={this.state.isPreviewing} 82 - onClick={e => this.handlePreview(e)} 82 + onClick={(e) => this.handlePreview(e)} 83 83 /> 84 84 </Grid.Column> 85 85 </Grid>
+13 -13
app/components/HomeComponent/index.tsx
··· 12 12 KERNEL_STATUS, 13 13 CONNECTION_STATUS, 14 14 DEVICE_AVAILABILITY, 15 - DEVICES 15 + DEVICES, 16 16 } from '../../constants/constants'; 17 17 import faceHouseIcon from '../../assets/common/FacesHouses.png'; 18 18 import stroopIcon from '../../assets/common/Stroop.png'; ··· 25 25 readWorkspaces, 26 26 readAndParseState, 27 27 openWorkspaceDir, 28 - deleteWorkspaceDir 28 + deleteWorkspaceDir, 29 29 } from '../../utils/filesystem/storage'; 30 30 import { 31 31 JupyterActions, 32 32 DeviceActions, 33 - ExperimentActions 33 + ExperimentActions, 34 34 } from '../../actions'; 35 35 36 36 import InputModal from '../InputModal'; ··· 45 45 // TODO: maybe change the recent and new labels, but not necessary right now 46 46 RECENT: 'MY EXPERIMENTS', 47 47 NEW: 'EXPERIMENT BANK', 48 - EXPLORE: 'EXPLORE EEG DATA' 48 + EXPLORE: 'EXPLORE EEG DATA', 49 49 }; 50 50 51 51 interface Props { ··· 83 83 recentWorkspaces: [], 84 84 isNewExperimentModalOpen: false, 85 85 isOverviewComponentOpen: false, 86 - overviewExperimentType: EXPERIMENTS.NONE 86 + overviewExperimentType: EXPERIMENTS.NONE, 87 87 }; 88 88 this.handleStepClick = this.handleStepClick.bind(this); 89 89 this.handleNewExperiment = this.handleNewExperiment.bind(this); ··· 106 106 handleNewExperiment(experimentType: EXPERIMENTS) { 107 107 if (experimentType === EXPERIMENTS.CUSTOM) { 108 108 this.setState({ 109 - isNewExperimentModalOpen: true 109 + isNewExperimentModalOpen: true, 110 110 }); 111 111 // If pre-designed experiment, load existing workspace 112 112 } else if (this.state.recentWorkspaces.includes(experimentType)) { ··· 116 116 this.props.ExperimentActions.CreateNewWorkspace({ 117 117 title: experimentType, 118 118 type: experimentType, 119 - paradigm: experimentType 119 + paradigm: experimentType, 120 120 }); 121 121 this.props.history.push(SCREENS.DESIGN.route); 122 122 } ··· 136 136 this.props.ExperimentActions.CreateNewWorkspace({ 137 137 title, 138 138 type: EXPERIMENTS.CUSTOM, 139 - paradigm: EXPERIMENTS.CUSTOM 139 + paradigm: EXPERIMENTS.CUSTOM, 140 140 }); 141 141 this.props.history.push(SCREENS.DESIGN.route); 142 142 } ··· 152 152 handleOpenOverview(type: EXPERIMENTS) { 153 153 this.setState({ 154 154 overviewExperimentType: type, 155 - isOverviewComponentOpen: true 155 + isOverviewComponentOpen: true, 156 156 }); 157 157 } 158 158 159 159 handleCloseOverview() { 160 160 this.setState({ 161 - isOverviewComponentOpen: false 161 + isOverviewComponentOpen: false, 162 162 }); 163 163 } 164 164 165 165 async handleDeleteWorkspace(dir) { 166 166 const options = { 167 167 buttons: ['No', 'Yes'], 168 - message: 'Do you really want to delete the experiment?' 168 + message: 'Do you really want to delete the experiment?', 169 169 }; 170 170 const response = await dialog.showMessageBox(options); 171 171 if (response.response === 1) { ··· 209 209 readAndParseState(b).params.dateModified || 0; 210 210 return bTime - aTime; 211 211 }) 212 - .map(dir => { 212 + .map((dir) => { 213 213 const { 214 - params: { dateModified } 214 + params: { dateModified }, 215 215 } = readAndParseState(dir); 216 216 return ( 217 217 <Table.Row key={dir} className={styles.experimentRow}>
+1 -1
app/components/InputCollect.tsx
··· 34 34 group: this.props.data && this.props.data.group, 35 35 session: this.props.data && this.props.data.session, 36 36 isSubjectError: false, 37 - isSessionError: false 37 + isSessionError: false, 38 38 }; 39 39 this.handleTextEntry = this.handleTextEntry.bind(this); 40 40 this.handleClose = this.handleClose.bind(this);
+2 -2
app/components/InputModal.tsx
··· 24 24 super(props); 25 25 this.state = { 26 26 enteredText: '', 27 - isError: false 27 + isError: false, 28 28 }; 29 29 this.handleTextEntry = debounce(this.handleTextEntry, 100).bind(this); 30 30 this.handleClose = this.handleClose.bind(this); ··· 49 49 } 50 50 51 51 handleEnterSubmit(event: object) { 52 - if (event['key'] === 'Enter') { 52 + if (event.key === 'Enter') { 53 53 this.handleClose(); 54 54 } 55 55 }
+2 -2
app/components/JupyterPlotWidget.tsx
··· 3 3 import { 4 4 richestMimetype, 5 5 standardDisplayOrder, 6 - standardTransforms 6 + standardTransforms, 7 7 } from '@nteract/transforms'; 8 8 import { isNil } from 'lodash'; 9 9 import { storeJupyterImage } from '../utils/filesystem/storage'; ··· 30 30 super(props); 31 31 this.state = { 32 32 rawData: '', 33 - mimeType: '' 33 + mimeType: '', 34 34 }; 35 35 this.handleSave = this.handleSave.bind(this); 36 36 }
+3 -3
app/components/PreviewExperimentComponent.tsx
··· 7 7 import { 8 8 MainTimeline, 9 9 Trial, 10 - ExperimentParameters 10 + ExperimentParameters, 11 11 } from '../constants/interfaces'; 12 12 13 13 interface Props { ··· 50 50 params: this.props.previewParams || this.props.params, 51 51 eventCallback: 52 52 PreviewExperimentComponent.insertPreviewLabJsCallback, 53 - on_finish: csv => { 53 + on_finish: (csv) => { 54 54 this.props.onEnd(); 55 - } 55 + }, 56 56 }} 57 57 /> 58 58 </div>
+2 -2
app/components/SecondaryNavComponent/index.tsx
··· 35 35 renderSteps() { 36 36 return ( 37 37 <> 38 - {Object.values(this.props.steps).map(stepTitle => ( 38 + {Object.values(this.props.steps).map((stepTitle) => ( 39 39 <SecondaryNavSegment 40 40 key={stepTitle} 41 41 title={stepTitle} ··· 72 72 <Dropdown.Menu className={styles.dropdownMenu}> 73 73 <Dropdown.Item 74 74 className={styles.dropdownItem} 75 - onClick={e => e.stopPropagation()} 75 + onClick={(e) => e.stopPropagation()} 76 76 > 77 77 <div>Enable EEG</div> 78 78 {this.props.enableEEGToggle}
+3 -3
app/components/SignalQualityIndicatorComponent.tsx
··· 44 44 } 45 45 46 46 this.signalQualitySubscription = observable.subscribe( 47 - epoch => { 48 - Object.keys(epoch.signalQuality).forEach(key => { 47 + (epoch) => { 48 + Object.keys(epoch.signalQuality).forEach((key) => { 49 49 d3.select(`#${key}`) 50 50 .attr('visibility', 'show') 51 51 .attr('stroke', '#000') ··· 55 55 .attr('fill', epoch.signalQuality[key]); 56 56 }); 57 57 }, 58 - error => new Error(`Error in signalQualitySubscription ${error}`) 58 + (error) => new Error(`Error in signalQualitySubscription ${error}`) 59 59 ); 60 60 } 61 61
+1 -1
app/components/TopNavComponent/PrimaryNavSegment.tsx
··· 10 10 order: number; 11 11 } 12 12 13 - const PrimaryNavSegment = props => { 13 + const PrimaryNavSegment = (props) => { 14 14 return ( 15 15 <Grid.Column 16 16 width={2}
+4 -4
app/components/TopNavComponent/index.tsx
··· 7 7 import PrimaryNavSegment from './PrimaryNavSegment'; 8 8 import { 9 9 readAndParseState, 10 - readWorkspaces 10 + readWorkspaces, 11 11 } from '../../utils/filesystem/storage'; 12 12 import BrainwavesIcon from '../../assets/common/Brainwaves_Icon_big.png'; 13 13 import { ExperimentActions } from '../../actions'; ··· 32 32 } 33 33 34 34 const routeOrder = Object.values(SCREENS).find( 35 - screen => screen.route === navSegmentScreen.route 35 + (screen) => screen.route === navSegmentScreen.route 36 36 )?.order; 37 37 const currentOrder = Object.values(SCREENS).find( 38 - screen => screen.route === this.props.location.pathname 38 + (screen) => screen.route === this.props.location.pathname 39 39 )?.order; 40 40 if (routeOrder && currentOrder && currentOrder > routeOrder) { 41 41 return styles.visitedNavColumn; ··· 88 88 }} 89 89 > 90 90 <Dropdown.Menu> 91 - {this.state.recentWorkspaces.map(workspace => ( 91 + {this.state.recentWorkspaces.map((workspace) => ( 92 92 <Dropdown.Item 93 93 key={workspace} 94 94 onClick={() => this.handleLoadRecentWorkspace(workspace)}
+6 -6
app/components/ViewerComponent.tsx
··· 5 5 MUSE_CHANNELS, 6 6 EMOTIV_CHANNELS, 7 7 DEVICES, 8 - VIEWER_DEFAULTS 8 + VIEWER_DEFAULTS, 9 9 } from '../constants/constants'; 10 10 11 11 const Mousetrap = require('mousetrap'); ··· 30 30 this.state = { 31 31 ...VIEWER_DEFAULTS, 32 32 channels: 33 - props.deviceType === DEVICES.EMOTIV ? EMOTIV_CHANNELS : MUSE_CHANNELS 33 + props.deviceType === DEVICES.EMOTIV ? EMOTIV_CHANNELS : MUSE_CHANNELS, 34 34 }; 35 35 this.graphView = null; 36 36 this.signalQualitySubscription = null; ··· 43 43 plottingInterval: this.props.plottingInterval, 44 44 channels: this.state.channels, 45 45 domain: this.state.domain, 46 - channelColours: this.state.channels.map(() => '#66B0A9') 46 + channelColours: this.state.channels.map(() => '#66B0A9'), 47 47 }); 48 48 this.setKeyListeners(); 49 49 if (!isNil(this.props.signalQualityObservable)) { ··· 63 63 channels: 64 64 this.props.deviceType === DEVICES.MUSE 65 65 ? MUSE_CHANNELS 66 - : EMOTIV_CHANNELS 66 + : EMOTIV_CHANNELS, 67 67 }); 68 68 } 69 69 if (this.state.channels !== prevState.channels) { ··· 98 98 this.signalQualitySubscription.unsubscribe(); 99 99 } 100 100 this.signalQualitySubscription = observable.subscribe( 101 - chunk => { 101 + (chunk) => { 102 102 this.graphView.send('newData', chunk); 103 103 }, 104 - error => new Error(`Error in epochSubscription ${error}`) 104 + (error) => new Error(`Error in epochSubscription ${error}`) 105 105 ); 106 106 } 107 107
+16 -19
app/components/d3Classes/EEGViewer.js
··· 28 28 29 29 updateData(epoch) { 30 30 const { 31 - info: { samplingRate, startTime } 31 + info: { samplingRate, startTime }, 32 32 } = epoch; 33 33 this.lastTimestamp = 34 34 startTime + epoch.data[0].length / (samplingRate / 1000); ··· 39 39 simplify( 40 40 epoch.data[i].map((dataPoint, index) => ({ 41 41 x: startTime + index / (samplingRate / 1000), 42 - y: dataPoint 42 + y: dataPoint, 43 43 })), 44 44 this.downsampling 45 45 ) 46 46 ) 47 - .filter(sample => sample.x >= this.firstTimestamp); 47 + .filter((sample) => sample.x >= this.firstTimestamp); 48 48 } 49 49 50 50 this.channelColours = this.channels.map( 51 - channelName => epoch.signalQuality[channelName] 51 + (channelName) => epoch.signalQuality[channelName] 52 52 ); 53 53 this.redraw(); 54 54 } ··· 76 76 } 77 77 78 78 autoScale() { 79 - this.channelMaxs = this.data.map(channelData => 79 + this.channelMaxs = this.data.map((channelData) => 80 80 EEGViewer.findExtreme(channelData, (a, b) => a > b) 81 81 ); 82 - this.channelMins = this.data.map(channelData => 82 + this.channelMins = this.data.map((channelData) => 83 83 EEGViewer.findExtreme(channelData, (a, b) => a < b) 84 84 ); 85 85 this.zoom = 1; ··· 88 88 89 89 resetData() { 90 90 this.data = new Array(this.channels.length).fill([ 91 - { x: this.lastTimestamp, y: 0 } 91 + { x: this.lastTimestamp, y: 0 }, 92 92 ]); 93 93 this.channelMaxs = new Array(this.channels.length).fill(100); 94 94 this.channelMins = new Array(this.channels.length).fill(-100); ··· 133 133 .range([ 134 134 (this.channels.length - 1) * (this.height / this.channels.length) + 135 135 this.height / this.channels.length / 2, 136 - this.height / this.channels.length / 2 136 + this.height / this.channels.length / 2, 137 137 ]); 138 138 } 139 139 ··· 145 145 .tickFormat((d, i) => this.channels[i].replace(/\s/g, '')) 146 146 .tickValues(d3.range(this.channels.length)); 147 147 148 - this.axisY = this.graph 149 - .append('g') 150 - .attr('class', 'axis') 151 - .call(this.yAxis); 148 + this.axisY = this.graph.append('g').attr('class', 'axis').call(this.yAxis); 152 149 } 153 150 154 151 addLines() { ··· 172 169 .attr('clip-path', 'url(#clip)'); 173 170 this.line = d3 174 171 .line() 175 - .x(d => this.xScale(d.x)) 176 - .y(d => this.yScaleLines(d.y)) 172 + .x((d) => this.xScale(d.x)) 173 + .y((d) => this.yScaleLines(d.y)) 177 174 .curve(d3.curveLinear) 178 - .defined(d => d.y); 175 + .defined((d) => d.y); 179 176 180 177 for (let i = 0; i < this.channels.length; i++) { 181 178 const channelData = this.data[i]; ··· 183 180 this.yScaleLines 184 181 .domain([ 185 182 this.channelMins[i] / this.zoom, 186 - this.channelMaxs[i] / this.zoom 183 + this.channelMaxs[i] / this.zoom, 187 184 ]) 188 185 .range(EEGViewer.getLineRange(i, this.channels.length, this.height)); 189 186 ··· 205 202 this.yScaleLines 206 203 .domain([ 207 204 this.channelMins[i] / this.zoom, 208 - this.channelMaxs[i] / this.zoom 205 + this.channelMaxs[i] / this.zoom, 209 206 ]) 210 207 .range(EEGViewer.getLineRange(i, this.channels.length, this.height)); 211 208 ··· 233 230 this.xScale 234 231 .domain([ 235 232 this.lastTimestamp, 236 - this.firstTimestamp + this.plottingInterval 233 + this.firstTimestamp + this.plottingInterval, 237 234 ]) 238 235 .range([this.width, 0]); 239 236 } ··· 253 250 this.yScaleLabels.range([ 254 251 (this.channels.length - 1) * (this.height / this.channels.length) + 255 252 this.height / this.channels.length / 2, 256 - this.height / this.channels.length / 2 253 + this.height / this.channels.length / 2, 257 254 ]); 258 255 this.axisY.call(this.yAxis); 259 256 this.addLines();
+1 -1
app/components/svgs/SignalQualityIndicatorSVG.tsx
··· 1 1 import React from 'react'; 2 2 3 - const SvgComponent = props => ( 3 + const SvgComponent = (props) => ( 4 4 <svg 5 5 id="SignalQualityIndicator" 6 6 data-name="SignalQualityIndicator"
+14 -14
app/constants/constants.ts
··· 6 6 STROOP = 'Stroop Task', 7 7 MULTI = 'Multi-tasking', 8 8 SEARCH = 'Visual search', 9 - CUSTOM = 'Custom' 9 + CUSTOM = 'Custom', 10 10 } 11 11 12 12 export const SCREENS = { ··· 17 17 RUN: { route: '/run', title: 'RUN', order: 5 }, 18 18 CLEAN: { route: '/clean', title: 'CLEAN', order: 3 }, 19 19 ANALYZE: { route: '/analyze', title: 'ANALYZE', order: 4 }, 20 - ANALYZEBEHAVIOR: { route: '/analyze', title: 'ANALYZE', order: 3 } 20 + ANALYZEBEHAVIOR: { route: '/analyze', title: 'ANALYZE', order: 3 }, 21 21 } as const; 22 22 23 23 export enum DEVICES { 24 24 NONE = 'NONE', 25 25 MUSE = 'MUSE', 26 26 EMOTIV = 'EMOTIV', 27 - GANGLION = 'GANGLION' // One day ;) 27 + GANGLION = 'GANGLION', // One day ;) 28 28 } 29 29 30 30 export enum CONNECTION_STATUS { ··· 34 34 NO_DEVICES = 'NO_DEVICES', 35 35 NOT_YET_CONNECTED = 'NOT_YET_CONNECTED', 36 36 SEARCHING = 'SEARCHING', 37 - BLUETOOTH_DISABLED = 'BLUETOOTH_DISABLED' 37 + BLUETOOTH_DISABLED = 'BLUETOOTH_DISABLED', 38 38 } 39 39 40 40 export enum KERNEL_STATUS { 41 41 OFFLINE = 'Offline', 42 42 BUSY = 'Busy', 43 43 IDLE = 'Idle', 44 - STARTING = 'Starting' 44 + STARTING = 'Starting', 45 45 } 46 46 47 47 export enum DEVICE_AVAILABILITY { 48 48 NONE = 'NONE', 49 49 SEARCHING = 'SEARCHING', 50 - AVAILABLE = 'AVAILABLE' 50 + AVAILABLE = 'AVAILABLE', 51 51 } 52 52 53 53 // Names of variables in the jupyter kernel 54 54 export enum JUPYTER_VARIABLE_NAMES { 55 55 RAW_EPOCHS = 'raw_epochs', 56 - CLEAN_EPOCHS = 'clean_epochs' 56 + CLEAN_EPOCHS = 'clean_epochs', 57 57 } 58 58 59 59 export const SEARCH_TIMER = 3000; ··· 65 65 STIMULUS_3 = 3, 66 66 STIMULUS_4 = 4, 67 67 TARGET = 2, 68 - NONTARGET = 1 68 + NONTARGET = 1, 69 69 } 70 70 71 71 export const CHANNELS = { ··· 89 89 AF7: { index: 1, color: '#7EA0C5' }, 90 90 AF8: { index: 2, color: '#8BD6E9' }, 91 91 TP10: { index: 3, color: '#66B0A9' }, 92 - AUX: { index: 4, color: '#E7789E' } 92 + AUX: { index: 4, color: '#E7789E' }, 93 93 } as const; 94 94 95 95 export const EMOTIV_CHANNELS = [ ··· 106 106 'FC6', 107 107 'F4', 108 108 'F8', 109 - 'AF4' 109 + 'AF4', 110 110 ]; 111 111 112 112 export const MUSE_CHANNELS = ['TP9', 'AF7', 'AF8', 'TP10', 'AUX']; ··· 119 119 export const VIEWER_DEFAULTS = { 120 120 domain: 5000, // ms 121 121 zoom: 1, 122 - autoScale: false 122 + autoScale: false, 123 123 } as const; 124 124 125 125 export enum SIGNAL_QUALITY { 126 126 BAD = '#ed5a5a', 127 127 OK = '#FFCD39', 128 128 GREAT = '#66B0A9', 129 - DISCONNECTED = '#BFBFBF' 129 + DISCONNECTED = '#BFBFBF', 130 130 } 131 131 132 132 export enum SIGNAL_QUALITY_THRESHOLDS { 133 133 BAD = 15, 134 134 OK = 10, 135 - GREAT = 1.5 // Below 1.5 usually indicates not connected to anything 135 + GREAT = 1.5, // Below 1.5 usually indicates not connected to anything 136 136 } 137 137 138 138 export enum FILE_TYPES { 139 139 STIMULUS_DIR = 'STIMULUS_DIR', 140 - TIMELINE = 'TIMELINE' 140 + TIMELINE = 'TIMELINE', 141 141 }
+2 -2
app/containers/AnalyzeContainer.ts
··· 9 9 type: state.experiment.type, 10 10 deviceType: state.device.deviceType, 11 11 isEEGEnabled: state.experiment.isEEGEnabled, 12 - ...state.jupyter 12 + ...state.jupyter, 13 13 }; 14 14 } 15 15 16 16 function mapDispatchToProps(dispatch) { 17 17 return { 18 18 ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 19 - JupyterActions: bindActionCreators(JupyterActions, dispatch) 19 + JupyterActions: bindActionCreators(JupyterActions, dispatch), 20 20 }; 21 21 } 22 22
+2 -2
app/containers/CleanContainer.ts
··· 11 11 group: state.experiment.group, 12 12 session: state.experiment.session, 13 13 deviceType: state.device.deviceType, 14 - ...state.jupyter 14 + ...state.jupyter, 15 15 }; 16 16 } 17 17 18 18 function mapDispatchToProps(dispatch) { 19 19 return { 20 20 ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 21 - JupyterActions: bindActionCreators(JupyterActions, dispatch) 21 + JupyterActions: bindActionCreators(JupyterActions, dispatch), 22 22 }; 23 23 } 24 24
+2 -2
app/containers/CollectContainer.ts
··· 6 6 function mapStateToProps(state) { 7 7 return { 8 8 ...state.device, 9 - ...state.experiment 9 + ...state.experiment, 10 10 }; 11 11 } 12 12 13 13 function mapDispatchToProps(dispatch) { 14 14 return { 15 15 DeviceActions: bindActionCreators(DeviceActions, dispatch), 16 - ExperimentActions: bindActionCreators(ExperimentActions, dispatch) 16 + ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 17 17 }; 18 18 } 19 19
+2 -2
app/containers/ExperimentDesignContainer.ts
··· 5 5 6 6 function mapStateToProps(state) { 7 7 return { 8 - ...state.experiment 8 + ...state.experiment, 9 9 }; 10 10 } 11 11 12 12 function mapDispatchToProps(dispatch) { 13 13 return { 14 - ExperimentActions: bindActionCreators(ExperimentActions, dispatch) 14 + ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 15 15 }; 16 16 } 17 17
+2 -2
app/containers/HomeContainer.ts
··· 6 6 function mapStateToProps(state) { 7 7 return { 8 8 ...state.device, 9 - kernelStatus: state.jupyter.kernelStatus 9 + kernelStatus: state.jupyter.kernelStatus, 10 10 }; 11 11 } 12 12 ··· 14 14 return { 15 15 DeviceActions: bindActionCreators(DeviceActions, dispatch), 16 16 JupyterActions: bindActionCreators(JupyterActions, dispatch), 17 - ExperimentActions: bindActionCreators(ExperimentActions, dispatch) 17 + ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 18 18 }; 19 19 } 20 20
+2 -2
app/containers/TopNavBarContainer.ts
··· 9 9 location: state.router.location, 10 10 isRunning: state.experiment.isRunning, 11 11 type: state.experiment.type, 12 - isEEGEnabled: state.experiment.isEEGEnabled 12 + isEEGEnabled: state.experiment.isEEGEnabled, 13 13 }; 14 14 } 15 15 16 16 function mapDispatchToProps(dispatch) { 17 17 return { 18 - ExperimentActions: bindActionCreators(ExperimentActions, dispatch) 18 + ExperimentActions: bindActionCreators(ExperimentActions, dispatch), 19 19 }; 20 20 } 21 21
+1 -1
app/epics/jupyterEpics.ts
··· 117 117 state$.value.jupyter.mainChannel.pipe( 118 118 map<object, JupyterActionType>((msg) => { 119 119 console.log(debugParseMessage(msg)); 120 - switch (msg['header']['msg_type']) { 120 + switch (msg.header.msg_type) { 121 121 case 'kernel_info_reply': 122 122 return JupyterActions.SetKernelInfo(msg); 123 123 case 'status':
-1
app/index.tsx
··· 1 1 import React, { Fragment } from 'react'; 2 2 import { render } from 'react-dom'; 3 3 import { AppContainer as ReactHotAppContainer } from 'react-hot-loader'; 4 - import Root from './containers/Root'; 5 4 import { configuredStore, history } from './store'; 6 5 import './app.global.css'; 7 6
+1 -1
app/menu.ts
··· 1 - /* eslint @typescript-eslint/ban-ts-ignore: off */ 1 + /* eslint @typescript-eslint/ban-ts-comment: off */ 2 2 import { 3 3 app, 4 4 Menu,
+11 -11
app/reducers/deviceReducer.ts
··· 4 4 DEVICES, 5 5 CONNECTION_STATUS, 6 6 DEVICE_AVAILABILITY, 7 - SIGNAL_QUALITY 7 + SIGNAL_QUALITY, 8 8 } from '../constants/constants'; 9 9 import { 10 10 DeviceInfo, 11 11 Device, 12 12 EEGData, 13 - SignalQualityData 13 + SignalQualityData, 14 14 } from '../constants/interfaces'; 15 15 import { DeviceActions } from '../actions'; 16 16 ··· 32 32 deviceAvailability: DEVICE_AVAILABILITY.NONE, 33 33 rawObservable: null, 34 34 signalQualityObservable: null, 35 - deviceType: DEVICES.EMOTIV 35 + deviceType: DEVICES.EMOTIV, 36 36 }; 37 37 38 - export default createReducer(initialState, builder => 38 + export default createReducer(initialState, (builder) => 39 39 builder 40 40 .addCase(DeviceActions.ConnectToDevice, (state, action) => { 41 41 return { 42 42 ...state, 43 - deviceType: action.payload 43 + deviceType: action.payload, 44 44 }; 45 45 }) 46 46 .addCase(DeviceActions.SetDeviceInfo, (state, action) => { 47 47 return { 48 48 ...state, 49 - connectedDevice: action.payload 49 + connectedDevice: action.payload, 50 50 }; 51 51 }) 52 52 53 53 .addCase(DeviceActions.SetAvailableDevices, (state, action) => { 54 54 return { 55 55 ...state, 56 - availableDevices: action.payload 56 + availableDevices: action.payload, 57 57 }; 58 58 }) 59 59 .addCase(DeviceActions.SetConnectionStatus, (state, action) => { 60 60 return { 61 61 ...state, 62 - connectionStatus: action.payload 62 + connectionStatus: action.payload, 63 63 }; 64 64 }) 65 65 .addCase(DeviceActions.SetDeviceAvailability, (state, action) => { 66 66 return { 67 67 ...state, 68 - deviceAvailability: action.payload 68 + deviceAvailability: action.payload, 69 69 }; 70 70 }) 71 71 72 72 .addCase(DeviceActions.SetRawObservable, (state, action) => { 73 73 return { 74 74 ...state, 75 - rawObservable: action.payload 75 + rawObservable: action.payload, 76 76 }; 77 77 }) 78 78 79 79 .addCase(DeviceActions.SetSignalQualityObservable, (state, action) => { 80 80 return { 81 81 ...state, 82 - signalQualityObservable: action.payload 82 + signalQualityObservable: action.payload, 83 83 }; 84 84 }) 85 85 .addCase(DeviceActions.Cleanup, (state, action) => {
+15 -15
app/reducers/experimentReducer.ts
··· 5 5 MainTimeline, 6 6 Trial, 7 7 ExperimentDescription, 8 - ExperimentParameters 8 + ExperimentParameters, 9 9 } from '../constants/interfaces'; 10 10 11 11 export interface ExperimentStateType { ··· 39 39 session: 1, 40 40 isRunning: false, 41 41 isEEGEnabled: false, 42 - description: { question: '', hypothesis: '', methods: '' } 42 + description: { question: '', hypothesis: '', methods: '' }, 43 43 }; 44 44 45 - export default createReducer(initialState, builder => 45 + export default createReducer(initialState, (builder) => 46 46 builder 47 47 .addCase(ExperimentActions.SetType, (state, action) => { 48 48 return { 49 49 ...state, 50 - type: action.payload 50 + type: action.payload, 51 51 }; 52 52 }) 53 53 54 54 .addCase(ExperimentActions.SetParadigm, (state, action) => { 55 55 return { 56 56 ...state, 57 - paradigm: action.payload 57 + paradigm: action.payload, 58 58 }; 59 59 }) 60 60 61 61 .addCase(ExperimentActions.SetSubject, (state, action) => { 62 62 return { 63 63 ...state, 64 - subject: action.payload 64 + subject: action.payload, 65 65 }; 66 66 }) 67 67 68 68 .addCase(ExperimentActions.SetGroup, (state, action) => { 69 69 return { 70 70 ...state, 71 - group: action.payload 71 + group: action.payload, 72 72 }; 73 73 }) 74 74 75 75 .addCase(ExperimentActions.SetSession, (state, action) => { 76 76 return { 77 77 ...state, 78 - session: action.payload 78 + session: action.payload, 79 79 }; 80 80 }) 81 81 82 82 .addCase(ExperimentActions.SetParams, (state, action) => { 83 83 return { 84 84 ...state, 85 - params: { ...state.params, ...action.payload } 85 + params: { ...state.params, ...action.payload }, 86 86 }; 87 87 }) 88 88 89 89 .addCase(ExperimentActions.SetTimeline, (state, action) => { 90 90 return { 91 91 ...state, 92 - ...action.payload 92 + ...action.payload, 93 93 }; 94 94 }) 95 95 96 96 .addCase(ExperimentActions.SetTitle, (state, action) => { 97 97 return { 98 98 ...state, 99 - title: action.payload 99 + title: action.payload, 100 100 }; 101 101 }) 102 102 103 103 .addCase(ExperimentActions.SetDescription, (state, action) => { 104 104 return { 105 105 ...state, 106 - description: action.payload 106 + description: action.payload, 107 107 }; 108 108 }) 109 109 110 110 .addCase(ExperimentActions.SetIsRunning, (state, action) => { 111 111 return { 112 112 ...state, 113 - isRunning: action.payload 113 + isRunning: action.payload, 114 114 }; 115 115 }) 116 116 117 117 .addCase(ExperimentActions.SetEEGEnabled, (state, action) => { 118 118 return { 119 119 ...state, 120 - isEEGEnabled: action.payload 120 + isEEGEnabled: action.payload, 121 121 }; 122 122 }) 123 123 124 124 .addCase(ExperimentActions.SetExperimentState, (state, action) => { 125 125 return { 126 - ...action.payload 126 + ...action.payload, 127 127 }; 128 128 }) 129 129 .addCase(
+11 -11
app/reducers/jupyterReducer.ts
··· 39 39 channelInfo: [], 40 40 psdPlot: null, 41 41 topoPlot: null, 42 - erpPlot: null 42 + erpPlot: null, 43 43 }; 44 44 45 - export default createReducer(initialState, builder => 45 + export default createReducer(initialState, (builder) => 46 46 builder 47 47 .addCase(JupyterActions.SetKernel, (state, action) => { 48 48 return { 49 49 ...state, 50 - kernel: action.payload 50 + kernel: action.payload, 51 51 }; 52 52 }) 53 53 .addCase(JupyterActions.SetKernelStatus, (state, action) => { 54 54 return { 55 55 ...state, 56 - kernelStatus: action.payload 56 + kernelStatus: action.payload, 57 57 }; 58 58 }) 59 59 .addCase(JupyterActions.SetMainChannel, (state, action) => { 60 60 return { 61 61 ...state, 62 - mainChannel: action.payload 62 + mainChannel: action.payload, 63 63 }; 64 64 }) 65 65 .addCase(JupyterActions.SetEpochInfo, (state, action) => { 66 66 return { 67 67 ...state, 68 - epochsInfo: action.payload 68 + epochsInfo: action.payload, 69 69 }; 70 70 }) 71 71 .addCase(JupyterActions.SetChannelInfo, (state, action) => { 72 72 return { 73 73 ...state, 74 - channelInfo: action.payload 74 + channelInfo: action.payload, 75 75 }; 76 76 }) 77 77 .addCase(JupyterActions.SetPSDPlot, (state, action) => { 78 78 return { 79 79 ...state, 80 - psdPlot: action.payload 80 + psdPlot: action.payload, 81 81 }; 82 82 }) 83 83 .addCase(JupyterActions.SetTopoPlot, (state, action) => { 84 84 return { 85 85 ...state, 86 - topoPlot: action.payload 86 + topoPlot: action.payload, 87 87 }; 88 88 }) 89 89 .addCase(JupyterActions.SetERPPlot, (state, action) => { 90 90 return { 91 91 ...state, 92 - erpPlot: action.payload 92 + erpPlot: action.payload, 93 93 }; 94 94 }) 95 95 .addCase(ExperimentActions.ExperimentCleanup, (state, action) => { ··· 97 97 ...state, 98 98 epochsInfo: [], 99 99 psdPlot: null, 100 - erpPlot: null 100 + erpPlot: null, 101 101 }; 102 102 }) 103 103 );
+1 -1
app/routes.tsx
··· 18 18 const PropsRoute = ({ component, ...rest }) => ( 19 19 <Route 20 20 {...rest} 21 - render={routeProps => renderMergedProps(component, routeProps, rest)} 21 + render={(routeProps) => renderMergedProps(component, routeProps, rest)} 22 22 /> 23 23 ); 24 24
+24 -13
app/utils/eeg/cortex.ts
··· 23 23 24 24 const CORTEX_URL = 'wss://localhost:6868'; 25 25 26 - const safeParse = msg => { 26 + const safeParse = (msg) => { 27 27 try { 28 28 return JSON.parse(msg); 29 29 } catch (_) { ··· 42 42 this.message = err.message; 43 43 this.code = err.code; 44 44 } 45 + 45 46 toString() { 46 47 return `${super.toString()} (${this.code})`; 47 48 } ··· 60 61 this._log('ws: Socket closed'); 61 62 }); 62 63 this.verbose = options.verbose !== null ? options.verbose : 1; 63 - this.handleError = error => { 64 + this.handleError = (error) => { 64 65 throw new JSONRPCError(error); 65 66 }; 66 67 67 68 this.ready = new Promise( 68 - resolve => this.ws.addEventListener('open', resolve), 69 + (resolve) => this.ws.addEventListener('open', resolve), 69 70 this.handleError 70 71 ) 71 72 .then(() => this._log('ws: Socket opened')) 72 73 .then(() => this.call('inspectApi')) 73 - .then(methods => { 74 - methods.forEach(m => { 74 + .then((methods) => { 75 + methods.forEach((m) => { 75 76 this.defineMethod(m.methodName, m.params); 76 77 }); 77 78 this._log(`rpc: Added ${methods.length} methods from inspectApi`); 78 79 return methods; 79 80 }); 80 81 } 82 + 81 83 _onmsg(msg) { 82 84 const data = safeParse(msg.data); 83 85 if (!data) return this._warn('unparseable message', msg); ··· 97 99 } 98 100 } else if ('sid' in data) { 99 101 const dataKeys = Object.keys(data).filter( 100 - k => k !== 'sid' && k !== 'time' && Array.isArray(data[k]) 102 + (k) => k !== 'sid' && k !== 'time' && Array.isArray(data[k]) 101 103 ); 102 104 dataKeys.forEach( 103 - k => 105 + (k) => 104 106 this.emit(k, data) || this._warn('no listeners for stream event', k) 105 107 ); 106 108 } else { 107 109 this._log('rpc: Unrecognised data', data); 108 110 } 109 111 } 112 + 110 113 _warn(...msg) { 111 114 if (this.verbose > 0) console.warn('[Cortex WARN]', ...msg); 112 115 } 116 + 113 117 _log(...msg) { 114 118 if (this.verbose > 1) console.log('[Cortex LOG]', ...msg); 115 119 } 120 + 116 121 _debug(...msg) { 117 122 if (this.verbose > 2) console.debug('[Cortex DEBUG]', ...msg); 118 123 } 124 + 119 125 init({ clientId, clientSecret, license, debit } = {}) { 120 126 const token = this.getUserLogin() 121 - .then(users => { 127 + .then((users) => { 122 128 if (users.length === 0) { 123 129 return Promise.reject(new Error('No logged in user')); 124 130 } ··· 134 140 clientId, 135 141 clientSecret, 136 142 license, 137 - debit 143 + debit, 138 144 }).then(({ cortexToken }) => { 139 145 this._log('init: Got auth token'); 140 146 this._debug('init: Auth token', cortexToken); ··· 145 151 146 152 return token; 147 153 } 154 + 148 155 close() { 149 - return new Promise(resolve => { 156 + return new Promise((resolve) => { 150 157 this.ws.close(); 151 158 this.ws.once('close', resolve); 152 159 }); 153 160 } 161 + 154 162 call(method, params = {}) { 155 163 const id = this.msgId++; 156 164 const msg = JSON.stringify({ jsonrpc: '2.0', method, params, id }); ··· 168 176 }; 169 177 }); 170 178 } 179 + 171 180 defineMethod(methodName, paramDefs = []) { 172 181 if (this[methodName]) return; 173 - const needsAuth = paramDefs.some(p => p.name === 'cortexToken'); 174 - const requiredParams = paramDefs.filter(p => p.required).map(p => p.name); 182 + const needsAuth = paramDefs.some((p) => p.name === 'cortexToken'); 183 + const requiredParams = paramDefs 184 + .filter((p) => p.required) 185 + .map((p) => p.name); 175 186 176 187 this[methodName] = (params = {}) => { 177 188 if (needsAuth && this.cortexToken && !params.cortexToken) { 178 189 params = { ...params, cortexToken: this.cortexToken }; 179 190 } 180 - const missingParams = requiredParams.filter(p => params[p] == null); 191 + const missingParams = requiredParams.filter((p) => params[p] == null); 181 192 if (missingParams.length > 0) { 182 193 return this.handleError( 183 194 new Error(
+15 -15
app/utils/eeg/emotiv.ts
··· 30 30 return devices; 31 31 }; 32 32 33 - export const connectToEmotiv = async device => { 33 + export const connectToEmotiv = async (device) => { 34 34 await client.ready; 35 35 36 36 // Authenticate ··· 39 39 clientId: CLIENT_ID, 40 40 clientSecret: CLIENT_SECRET, 41 41 license: LICENSE_ID, 42 - debit: 1 42 + debit: 1, 43 43 }); 44 44 } catch (err) { 45 45 toast.error(`Authentication failed. ${err.message}`); ··· 56 56 try { 57 57 const newSession = await client.createSession({ 58 58 status: 'active', 59 - headset: device.id 59 + headset: device.id, 60 60 }); 61 61 session = newSession; 62 62 63 63 return { 64 64 name: session.headset.id, 65 65 samplingRate: session.headset.settings.eegRate, 66 - channels: EMOTIV_CHANNELS 66 + channels: EMOTIV_CHANNELS, 67 67 }; 68 68 } catch (err) { 69 69 toast.error(`Session creation failed. ${err.message} `); ··· 74 74 console.log('disconnecting form emotiv'); 75 75 const sessionStatus = await client.updateSession({ 76 76 session: session.id, 77 - status: 'close' 77 + status: 'close', 78 78 }); 79 79 return sessionStatus; 80 80 }; ··· 87 87 try { 88 88 await client.subscribe({ 89 89 session: session.id, 90 - streams: ['eeg', 'dev'] 90 + streams: ['eeg', 'dev'], 91 91 }); 92 92 } catch (err) { 93 93 toast.error(`EEG connection failed. ${err.message}`); ··· 98 98 }; 99 99 100 100 // Creates an observable that will epoch, filter, and add signal quality to EEG stream 101 - export const createEmotivSignalQualityObservable = rawObservable => { 101 + export const createEmotivSignalQualityObservable = (rawObservable) => { 102 102 // @ts-ignore 103 103 const signalQualityObservable = fromEvent(client, 'dev'); 104 104 const samplingRate = 128; ··· 107 107 return rawObservable.pipe( 108 108 addInfo({ 109 109 samplingRate, 110 - channels 110 + channels, 111 111 }), 112 112 epoch({ 113 113 duration: intervalSamples, 114 - interval: intervalSamples 114 + interval: intervalSamples, 115 115 }), 116 116 bandpassFilter({ 117 117 nbChannels: channels.length, 118 118 lowCutoff: 1, 119 - highCutoff: 50 119 + highCutoff: 50, 120 120 }), 121 121 withLatestFrom(signalQualityObservable, integrateSignalQuality), 122 122 parseEmotivSignalQuality(), ··· 131 131 export const createEmotivRecord = (subjectName, sessionNumber) => { 132 132 client.createRecord({ 133 133 session: session.id, 134 - title: `${subjectName}_${sessionNumber}` 134 + title: `${subjectName}_${sessionNumber}`, 135 135 }); 136 136 }; 137 137 ··· 146 146 // 14 EEG channels in data 147 147 // timestamp in ms 148 148 // Event marker in marker if present 149 - const createEEGSample = eegEvent => { 149 + const createEEGSample = (eegEvent) => { 150 150 const prunedArray = new Array(EMOTIV_CHANNELS.length); 151 151 for (let i = 0; i < EMOTIV_CHANNELS.length; i++) { 152 152 prunedArray[i] = eegEvent.eeg[i + 2]; ··· 165 165 ...newEpoch, 166 166 signalQuality: { 167 167 ...devSample.dev[2].map((signalQuality, index) => ({ 168 - [EMOTIV_CHANNELS[index]]: signalQuality 169 - })) 170 - } 168 + [EMOTIV_CHANNELS[index]]: signalQuality, 169 + })), 170 + }, 171 171 });
+13 -13
app/utils/eeg/muse.ts
··· 4 4 addInfo, 5 5 epoch, 6 6 bandpassFilter, 7 - addSignalQuality 7 + addSignalQuality, 8 8 } from '@neurosity/pipes'; 9 9 import { release } from 'os'; 10 10 import { MUSE_SERVICE, MuseClient, zipSamples } from 'muse-js'; ··· 13 13 import { 14 14 MUSE_SAMPLING_RATE, 15 15 MUSE_CHANNELS, 16 - PLOTTING_INTERVAL 16 + PLOTTING_INTERVAL, 17 17 } from '../../constants/constants'; 18 18 19 19 const INTER_SAMPLE_INTERVAL = -(1 / 256) * 1000; ··· 41 41 } 42 42 // @ts-ignore 43 43 device = await bluetooth.requestDevice({ 44 - filters: [{ services: [MUSE_SERVICE] }] 44 + filters: [{ services: [MUSE_SERVICE] }], 45 45 }); 46 46 } else { 47 47 device = await navigator.bluetooth.requestDevice({ 48 - filters: [{ services: [MUSE_SERVICE] }] 48 + filters: [{ services: [MUSE_SERVICE] }], 49 49 }); 50 50 } 51 51 return [device]; 52 52 }; 53 53 54 54 // Attempts to connect to a muse device. If successful, returns a device info object 55 - export const connectToMuse = async device => { 55 + export const connectToMuse = async (device) => { 56 56 if (process.platform === 'win32') { 57 57 const gatt = await device.gatt.connect(); 58 58 await client.connect(gatt); ··· 62 62 return { 63 63 name: client.deviceName, 64 64 samplingRate: MUSE_SAMPLING_RATE, 65 - channels: MUSE_CHANNELS 65 + channels: MUSE_CHANNELS, 66 66 }; 67 67 }; 68 68 ··· 74 74 const eegStream = await client.eegReadings; 75 75 const markers = await client.eventMarkers.pipe(startWith({ timestamp: 0 })); 76 76 return from(zipSamples(eegStream)).pipe( 77 - filter(sample => !sample.data.includes(NaN)), 77 + filter((sample) => !sample.data.includes(NaN)), 78 78 withLatestFrom(markers, synchronizeTimestamp), 79 79 share() 80 80 ); ··· 90 90 return rawObservable.pipe( 91 91 addInfo({ 92 92 samplingRate, 93 - channelNames 93 + channelNames, 94 94 }), 95 95 epoch({ 96 96 duration: intervalSamples, 97 - interval: intervalSamples 97 + interval: intervalSamples, 98 98 }), 99 99 bandpassFilter({ 100 100 nbChannels: channelNames.length, 101 101 lowCutoff: 1, 102 - highCutoff: 50 102 + highCutoff: 50, 103 103 }), 104 104 addSignalQuality(), 105 105 parseMuseSignalQuality() ··· 116 116 117 117 const synchronizeTimestamp = (eegSample, marker) => { 118 118 if ( 119 - eegSample['timestamp'] - marker['timestamp'] < 0 && 120 - eegSample['timestamp'] - marker['timestamp'] >= INTER_SAMPLE_INTERVAL 119 + eegSample.timestamp - marker.timestamp < 0 && 120 + eegSample.timestamp - marker.timestamp >= INTER_SAMPLE_INTERVAL 121 121 ) { 122 - return { ...eegSample, marker: marker['value'] }; 122 + return { ...eegSample, marker: marker.value }; 123 123 } 124 124 return eegSample; 125 125 };
+5 -5
app/utils/eeg/pipes.ts
··· 2 2 import { map } from 'rxjs/operators'; 3 3 import { 4 4 SIGNAL_QUALITY, 5 - SIGNAL_QUALITY_THRESHOLDS 5 + SIGNAL_QUALITY_THRESHOLDS, 6 6 } from '../../constants/constants'; 7 7 8 8 export const parseMuseSignalQuality = () => 9 9 pipe( 10 - map(epoch => ({ 10 + map((epoch) => ({ 11 11 ...epoch, 12 12 signalQuality: object.assign( 13 13 {}, ··· 25 25 return { [channelName]: SIGNAL_QUALITY.DISCONNECTED }; 26 26 } 27 27 ) 28 - ) 28 + ), 29 29 })) 30 30 ); 31 31 32 32 export const parseEmotivSignalQuality = () => 33 33 pipe( 34 - map(epoch => ({ 34 + map((epoch) => ({ 35 35 ...epoch, 36 36 signalQuality: object.assign( 37 37 {}, ··· 49 49 return { [channelName]: SIGNAL_QUALITY.BAD }; 50 50 } 51 51 ) 52 - ) 52 + ), 53 53 })) 54 54 );
+6 -6
app/utils/filesystem/dialog.ts
··· 17 17 } 18 18 }; 19 19 20 - const selectTimeline = event => { 20 + const selectTimeline = (event) => { 21 21 dialog.showOpenDialog( 22 22 { 23 23 title: 'Select a jsPsych timeline file', 24 - properties: ['openFile', 'promptToCreate'] 24 + properties: ['openFile', 'promptToCreate'], 25 25 }, 26 - filePaths => { 26 + (filePaths) => { 27 27 if (filePaths) { 28 28 event.sender.send('loadDialogReply', filePaths[0]); 29 29 } ··· 31 31 ); 32 32 }; 33 33 34 - const selectStimulusFolder = event => { 34 + const selectStimulusFolder = (event) => { 35 35 dialog.showOpenDialog( 36 36 { 37 37 title: 'Select a folder of images', 38 - properties: ['openDirectory'] 38 + properties: ['openDirectory'], 39 39 }, 40 - dir => { 40 + (dir) => { 41 41 if (dir) { 42 42 event.sender.send('loadDialogReply', dir[0]); 43 43 } else {
+1 -1
app/utils/filesystem/select.ts
··· 6 6 import { FILE_TYPES } from '../../constants/constants'; 7 7 8 8 export const loadFromSystemDialog = (fileType: FILE_TYPES) => 9 - new Promise(resolve => { 9 + new Promise((resolve) => { 10 10 ipcRenderer.send('loadDialog', fileType); 11 11 ipcRenderer.on('loadDialogReply', (_, result) => { 12 12 resolve(result);
+25 -25
app/utils/filesystem/storage.ts
··· 52 52 ...state, 53 53 subject: '', 54 54 group: '', 55 - session: 1 55 + session: 1, 56 56 }; 57 57 if (!timestampedState.title) { 58 58 return; ··· 74 74 const dir = path.join(getWorkspaceDir(title), 'Data', subject, 'Behavior'); 75 75 const filename = `${subject}-${group}-${session}-behavior.csv`; 76 76 mkdirPathSync(dir); 77 - fs.writeFile(path.join(dir, filename), csv, err => { 77 + fs.writeFile(path.join(dir, filename), csv, (err) => { 78 78 if (err) { 79 79 console.error(err); 80 80 } ··· 90 90 const dir = path.join(getWorkspaceDir(title), 'Results', 'Images'); 91 91 const filename = `${imageTitle}.png`; 92 92 mkdirPathSync(dir); 93 - fs.writeFile(path.join(dir, filename), rawData, err => { 93 + fs.writeFile(path.join(dir, filename), rawData, (err) => { 94 94 if (err) { 95 95 console.error(err); 96 96 } ··· 105 105 try { 106 106 return fs 107 107 .readdirSync(workspaces) 108 - .filter(workspace => workspace !== '.DS_Store'); 108 + .filter((workspace) => workspace !== '.DS_Store'); 109 109 } catch (e) { 110 110 if (e.code === 'ENOENT') { 111 111 mkdirPathSync(workspaces); ··· 120 120 try { 121 121 const files = await recursive(getWorkspaceDir(title)); 122 122 const rawFiles = files 123 - .filter(filepath => filepath.slice(-7).includes('raw.csv')) 124 - .map(filepath => ({ 123 + .filter((filepath) => filepath.slice(-7).includes('raw.csv')) 124 + .map((filepath) => ({ 125 125 name: path.basename(filepath), 126 - path: filepath 126 + path: filepath, 127 127 })); 128 128 return rawFiles; 129 129 } catch (e) { ··· 139 139 try { 140 140 const files = await recursive(getWorkspaceDir(title)); 141 141 return files 142 - .filter(filepath => filepath.slice(-7).includes('epo.fif')) 143 - .map(filepath => ({ 142 + .filter((filepath) => filepath.slice(-7).includes('epo.fif')) 143 + .map((filepath) => ({ 144 144 name: path.basename(filepath), 145 - path: filepath 145 + path: filepath, 146 146 })); 147 147 } catch (e) { 148 148 console.log(e); ··· 155 155 try { 156 156 const files = await recursive(getWorkspaceDir(title)); 157 157 const behaviorFiles = files 158 - .filter(filepath => filepath.slice(-12).includes('behavior.csv')) 159 - .map(filepath => ({ 158 + .filter((filepath) => filepath.slice(-12).includes('behavior.csv')) 159 + .map((filepath) => ({ 160 160 name: path.basename(filepath), 161 - path: filepath 161 + path: filepath, 162 162 })); 163 163 return behaviorFiles; 164 164 } catch (e) { ··· 174 174 try { 175 175 return JSON.parse( 176 176 fs.readFileSync(path.join(workspaces, dir, 'appState.json'), { 177 - encoding: 'string' 177 + encoding: 'string', 178 178 }) 179 179 ); 180 180 } catch (e) { ··· 187 187 188 188 // Reads a list of images that are in a directory 189 189 export const readImages = (dir: string) => 190 - fs.readdirSync(dir).filter(filename => { 190 + fs.readdirSync(dir).filter((filename) => { 191 191 const extension = filename.slice(-3).toLowerCase(); 192 192 return ( 193 193 extension === 'png' || ··· 201 201 export const getImages = (params: ExperimentParameters) => 202 202 fs 203 203 .readdirSync(params.stimulus1.dir) 204 - .map(filename => path.join(params.stimulus1.dir, filename)) 204 + .map((filename) => path.join(params.stimulus1.dir, filename)) 205 205 .concat( 206 206 fs 207 207 .readdirSync(params.stimulus2.dir) 208 - .map(filename => path.join(params.stimulus2.dir, filename)) 208 + .map((filename) => path.join(params.stimulus2.dir, filename)) 209 209 ); 210 210 211 211 // ----------------------------------------------------------------------------------------------- 212 212 // Util 213 213 214 214 // Creates a directory path if it doesn't exist 215 - export const mkdirPathSync = dirPath => { 215 + export const mkdirPathSync = (dirPath) => { 216 216 mkdirp.sync(dirPath); 217 217 }; 218 218 219 219 export const getSubjectNamesFromFiles = (filePaths: Array<string>) => 220 220 filePaths 221 - .map(filePath => path.basename(filePath)) 222 - .map(fileName => fileName.substring(0, fileName.indexOf('-'))); 221 + .map((filePath) => path.basename(filePath)) 222 + .map((fileName) => fileName.substring(0, fileName.indexOf('-'))); 223 223 224 224 // Read CSV files with behavioral data and return an object 225 225 export const readBehaviorData = (files: Array<string>) => { 226 226 try { 227 - return files.map(file => { 227 + return files.map((file) => { 228 228 const csv = fs.readFileSync(file, 'utf-8'); 229 229 const obj = convertCSVToObject(csv); 230 230 obj.meta.datafile = file; ··· 244 244 const saveFileOnDisk = (data, title) => { 245 245 dialog.showSaveDialog({ 246 246 title: 'Select a folder to save the data', 247 - defaultPath: path.join(getWorkspaceDir(title), 'Data', `aggregated.csv`) 247 + defaultPath: path.join(getWorkspaceDir(title), 'Data', `aggregated.csv`), 248 248 }); 249 249 }; 250 250 251 251 // convert a csv file to an object with Papaparse 252 - const convertCSVToObject = csv => { 252 + const convertCSVToObject = (csv) => { 253 253 const data = Papa.parse(csv, { 254 - header: true 254 + header: true, 255 255 }); 256 256 return data; 257 257 }; 258 258 259 259 // convert an object to a csv file with Papaparse 260 - const convertObjectToSCV = data => { 260 + const convertObjectToSCV = (data) => { 261 261 const csv = Papa.unparse(data); 262 262 return csv; 263 263 };
+1 -1
app/utils/filesystem/write.ts
··· 47 47 writeStream.write(`${eegData.data[i].toString()},`); // Round data 48 48 } 49 49 if (has(eegData, 'marker')) { 50 - writeStream.write(`${eegData['marker']}\n`); 50 + writeStream.write(`${eegData.marker}\n`); 51 51 } else { 52 52 writeStream.write(`0\n`); 53 53 }
+1 -1
app/utils/jupyter/functions.ts
··· 4 4 JSON.parse(string.replace(/'/g, '"')); 5 5 6 6 export const parseKernelStatus = (msg: object) => { 7 - switch (msg['content']['execution_state']) { 7 + switch (msg.content.execution_state) { 8 8 case 'busy': 9 9 return KERNEL_STATUS.BUSY; 10 10 case 'idle':
+2 -2
app/utils/jupyter/pipes.ts
··· 9 9 map(() => state$.value.jupyter.mainChannel.next(executeRequest(command))) 10 10 ); 11 11 12 - export const awaitOkMessage = action$ => 12 + export const awaitOkMessage = (action$) => 13 13 pipe( 14 14 mergeMap(() => 15 15 action$.ofType(JupyterActions.ReceiveExecuteReply.type).pipe( 16 16 pluck('payload'), 17 17 filter<any>( 18 - msg => msg.channel === 'shell' && msg.content.status === 'ok' 18 + (msg) => msg.channel === 'shell' && msg.content.status === 'ok' 19 19 ), 20 20 take(1) 21 21 )
+6 -6
app/utils/labjs/index.tsx
··· 32 32 faceshouses.parameters = props.settings.params; 33 33 faceshouses.parameters.title = props.settings.title; 34 34 faceshouses.files = props.settings.params.stimuli 35 - .map(image => ({ 35 + .map((image) => ({ 36 36 [path.join(image.dir, image.filename)]: path.join( 37 37 image.dir, 38 38 image.filename 39 - ) 39 + ), 40 40 })) 41 41 .reduce((obj, item) => { 42 42 // return { ...obj, item }; ?? ··· 50 50 custom.parameters = props.settings.params; 51 51 custom.parameters.title = props.settings.title; 52 52 custom.files = props.settings.params.stimuli 53 - .map(image => ({ 53 + .map((image) => ({ 54 54 [path.join(image.dir, image.filename)]: path.join( 55 55 image.dir, 56 56 image.filename 57 - ) 57 + ), 58 58 })) 59 59 .reduce((obj, item) => { 60 60 // return { ...obj, item }; ?? ··· 70 70 this.study = undefined; 71 71 props.settings.on_finish(csv); 72 72 }); 73 - this.study.parameters.callbackForEEG = e => { 73 + this.study.parameters.callbackForEEG = (e) => { 74 74 props.settings.eventCallback(e, new Date().getTime()); 75 75 }; 76 - this.study.options.events['keydown'] = async e => { 76 + this.study.options.events.keydown = async (e) => { 77 77 if (e.code === 'Escape') { 78 78 if (this.study) { 79 79 await this.study.internals.controller.audioContext.close();
+16 -16
app/utils/labjs/protocols/custom.ts
··· 34 34 { 35 35 name: 'Link 1', 36 36 address: 37 - 'https://www.cnn.com/videos/health/2011/01/04/sacks.face.blindness.cnn' 38 - } 37 + 'https://www.cnn.com/videos/health/2011/01/04/sacks.face.blindness.cnn', 38 + }, 39 39 ], 40 40 protocal_links: [], 41 41 params: { ··· 57 57 dir: '', 58 58 title: 'Condition 1', 59 59 type: EVENTS.STIMULUS_1, 60 - response: '' 60 + response: '', 61 61 }, 62 62 stimulus2: { 63 63 dir: '', 64 64 title: 'Condition 2', 65 65 type: EVENTS.STIMULUS_2, 66 - response: '' 66 + response: '', 67 67 }, 68 68 stimulus3: { 69 69 dir: '', 70 70 title: '', 71 71 type: 3, 72 - response: '' 72 + response: '', 73 73 }, 74 74 stimulus4: { 75 75 dir: '', 76 76 title: '', 77 77 type: 4, 78 - response: '' 78 + response: '', 79 79 }, 80 - stimuli: [] 80 + stimuli: [], 81 81 }, 82 82 mainTimeline: ['intro', 'faceHouseTimeline', 'end'], // array of trial and timeline ids 83 83 trials: { 84 84 intro: { 85 85 type: 'callback-html-display', 86 86 id: 'intro', 87 - post_trial_gap: 1000 87 + post_trial_gap: 1000, 88 88 }, 89 89 end: { 90 90 id: 'end', 91 91 type: 'callback-html-display', 92 92 stimulus: 'Thanks for participating. Press any key to continue', 93 93 response_ends_trial: true, 94 - post_trial_gap: 500 95 - } 94 + post_trial_gap: 500, 95 + }, 96 96 }, 97 97 timelines: { 98 98 faceHouseTimeline: { ··· 102 102 id: 'interTrial', 103 103 type: 'callback-image-display', 104 104 stimulus: fixation, 105 - response_ends_trial: false 105 + response_ends_trial: false, 106 106 }, 107 107 { 108 108 id: 'trial', 109 - response_ends_trial: false 110 - } 111 - ] 112 - } 113 - } 109 + response_ends_trial: false, 110 + }, 111 + ], 112 + }, 113 + }, 114 114 });
+19 -19
app/utils/labjs/protocols/faceshouses.ts
··· 68 68 'House27', 69 69 'House28', 70 70 'House29', 71 - 'House30' 72 - ].map(s => ({ 71 + 'House30', 72 + ].map((s) => ({ 73 73 condition: s.startsWith('Face') ? 'Face' : 'House', 74 74 dir: s.startsWith('Face') ? facesDir : housesDir, 75 75 filename: `${s}.jpg`, 76 76 name: s, 77 77 response: s.startsWith('Face') ? '1' : '9', 78 78 phase: 'main', 79 - type: s.startsWith('Face') ? EVENTS.STIMULUS_1 : EVENTS.STIMULUS_2 79 + type: s.startsWith('Face') ? EVENTS.STIMULUS_1 : EVENTS.STIMULUS_2, 80 80 })); 81 81 82 82 // phase: ['Face1', 'House1'].includes(s) ? 'practice' : 'main', ··· 109 109 { 110 110 name: 'Link 1', 111 111 address: 112 - 'https://www.cnn.com/videos/health/2011/01/04/sacks.face.blindness.cnn' 113 - } 112 + 'https://www.cnn.com/videos/health/2011/01/04/sacks.face.blindness.cnn', 113 + }, 114 114 ], 115 115 protocal_links: [], 116 116 params: { ··· 132 132 dir: facesDir, 133 133 title: 'Face', 134 134 type: EVENTS.STIMULUS_1, 135 - response: '1' 135 + response: '1', 136 136 }, 137 137 stimulus2: { 138 138 dir: housesDir, 139 139 title: 'House', 140 140 type: EVENTS.STIMULUS_2, 141 - response: '9' 141 + response: '9', 142 142 }, 143 143 stimulus3: { 144 144 dir: '', 145 145 title: '', 146 146 type: 3, 147 - response: '' 147 + response: '', 148 148 }, 149 149 stimulus4: { 150 150 dir: '', 151 151 title: '', 152 152 type: 4, 153 - response: '' 153 + response: '', 154 154 }, 155 - stimuli 155 + stimuli, 156 156 }, 157 157 mainTimeline: ['intro', 'faceHouseTimeline', 'end'], // array of trial and timeline ids 158 158 trials: { 159 159 intro: { 160 160 type: 'callback-html-display', 161 161 id: 'intro', 162 - post_trial_gap: 1000 162 + post_trial_gap: 1000, 163 163 }, 164 164 end: { 165 165 id: 'end', 166 166 type: 'callback-html-display', 167 167 stimulus: 'Thanks for participating. Press any key to continue', 168 168 response_ends_trial: true, 169 - post_trial_gap: 500 170 - } 169 + post_trial_gap: 500, 170 + }, 171 171 }, 172 172 timelines: { 173 173 faceHouseTimeline: { ··· 177 177 id: 'interTrial', 178 178 type: 'callback-image-display', 179 179 stimulus: fixation, 180 - response_ends_trial: false 180 + response_ends_trial: false, 181 181 }, 182 182 { 183 183 id: 'trial', 184 - response_ends_trial: false 185 - } 186 - ] 187 - } 188 - } 184 + response_ends_trial: false, 185 + }, 186 + ], 187 + }, 188 + }, 189 189 });
+15 -15
app/utils/labjs/protocols/multi.ts
··· 35 35 { 36 36 name: 'Link 1', 37 37 address: 38 - 'https://www.scientificamerican.com/podcast/episode/the-myth-of-multitasking-09-07-15/' 38 + 'https://www.scientificamerican.com/podcast/episode/the-myth-of-multitasking-09-07-15/', 39 39 }, 40 40 { 41 41 name: 'Link 2', 42 42 address: 43 - 'https://www.scientificamerican.com/article/multitasking-two-tasks/' 44 - } 43 + 'https://www.scientificamerican.com/article/multitasking-two-tasks/', 44 + }, 45 45 ], 46 46 protocal_links: [], 47 47 params: { ··· 56 56 dir: facesDir, 57 57 title: 'No switching', 58 58 type: EVENTS.STIMULUS_1, 59 - response: '1' 59 + response: '1', 60 60 }, 61 61 stimulus2: { 62 62 dir: housesDir, 63 63 title: 'Switching', 64 64 type: EVENTS.STIMULUS_2, 65 - response: '9' 66 - } 65 + response: '9', 66 + }, 67 67 }, 68 68 mainTimeline: ['intro', 'multiTaskingTimeline', 'end'], // array of trial and timeline ids 69 69 trials: { 70 70 intro: { 71 71 type: 'callback-html-display', 72 72 id: 'intro', 73 - post_trial_gap: 1000 73 + post_trial_gap: 1000, 74 74 }, 75 75 end: { 76 76 id: 'end', 77 77 type: 'callback-html-display', 78 78 stimulus: 'Thanks for participating. Press any key to continue', 79 79 response_ends_trial: true, 80 - post_trial_gap: 500 81 - } 80 + post_trial_gap: 500, 81 + }, 82 82 }, 83 83 timelines: { 84 84 faceHouseTimeline: { ··· 88 88 id: 'interTrial', 89 89 type: 'callback-image-display', 90 90 stimulus: fixation, 91 - response_ends_trial: false 91 + response_ends_trial: false, 92 92 }, 93 93 { 94 94 id: 'trial', 95 - response_ends_trial: false 96 - } 97 - ] 98 - } 99 - } 95 + response_ends_trial: false, 96 + }, 97 + ], 98 + }, 99 + }, 100 100 });
+12 -12
app/utils/labjs/protocols/search.ts
··· 48 48 dir: facesDir, 49 49 title: '5 and 10 letters', 50 50 type: EVENTS.STIMULUS_1, 51 - response: '1' 51 + response: '1', 52 52 }, 53 53 stimulus2: { 54 54 dir: housesDir, 55 55 title: '15 and 20 letters', 56 56 type: EVENTS.STIMULUS_2, 57 - response: '9' 58 - } 57 + response: '9', 58 + }, 59 59 }, 60 60 mainTimeline: ['intro', 'visualSearchTimeline', 'end'], // array of trial and timeline ids 61 61 trials: { 62 62 intro: { 63 63 type: 'callback-html-display', 64 64 id: 'intro', 65 - post_trial_gap: 1000 65 + post_trial_gap: 1000, 66 66 }, 67 67 end: { 68 68 id: 'end', 69 69 type: 'callback-html-display', 70 70 stimulus: 'Thanks for participating. Press any key to continue', 71 71 response_ends_trial: true, 72 - post_trial_gap: 500 73 - } 72 + post_trial_gap: 500, 73 + }, 74 74 }, 75 75 timelines: { 76 76 faceHouseTimeline: { ··· 80 80 id: 'interTrial', 81 81 type: 'callback-image-display', 82 82 stimulus: fixation, 83 - response_ends_trial: false 83 + response_ends_trial: false, 84 84 }, 85 85 { 86 86 id: 'trial', 87 - response_ends_trial: false 88 - } 89 - ] 90 - } 91 - } 87 + response_ends_trial: false, 88 + }, 89 + ], 90 + }, 91 + }, 92 92 });
+14 -14
app/utils/labjs/protocols/stroop.ts
··· 38 38 { 39 39 name: 'Link 1', 40 40 address: 41 - 'https://www.psychologytoday.com/us/blog/play-in-mind/201204/when-red-looks-blue-and-yes-means-no' 42 - } 41 + 'https://www.psychologytoday.com/us/blog/play-in-mind/201204/when-red-looks-blue-and-yes-means-no', 42 + }, 43 43 ], 44 44 protocal_links: [], 45 45 params: { ··· 54 54 dir: facesDir, 55 55 title: 'Incongruent', 56 56 type: EVENTS.STIMULUS_1, 57 - response: '1' 57 + response: '1', 58 58 }, 59 59 stimulus2: { 60 60 dir: housesDir, 61 61 title: 'Congruent', 62 62 type: EVENTS.STIMULUS_2, 63 - response: '9' 64 - } 63 + response: '9', 64 + }, 65 65 }, 66 66 mainTimeline: ['intro', 'stroopTimeline', 'end'], // array of trial and timeline ids 67 67 trials: { 68 68 intro: { 69 69 type: 'callback-html-display', 70 70 id: 'intro', 71 - post_trial_gap: 1000 71 + post_trial_gap: 1000, 72 72 }, 73 73 end: { 74 74 id: 'end', 75 75 type: 'callback-html-display', 76 76 stimulus: 'Thanks for participating. Press any key to continue', 77 77 response_ends_trial: true, 78 - post_trial_gap: 500 79 - } 78 + post_trial_gap: 500, 79 + }, 80 80 }, 81 81 timelines: { 82 82 faceHouseTimeline: { ··· 86 86 id: 'interTrial', 87 87 type: 'callback-image-display', 88 88 stimulus: fixation, 89 - response_ends_trial: false 89 + response_ends_trial: false, 90 90 }, 91 91 { 92 92 id: 'trial', 93 - response_ends_trial: false 94 - } 95 - ] 96 - } 97 - } 93 + response_ends_trial: false, 94 + }, 95 + ], 96 + }, 97 + }, 98 98 });