diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..20470851 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,38 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + + # Setup Node + - name: Setup Node + uses: actions/setup-node@v1 + with: + node-version: '12.x' + + # Install Dependencies + - name: Install Dependencies + run: npm install + + # Build + - name: Build + run: npm run build diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..85fb701e --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events*.json +speed-measure-plugin*.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db + +**/.firebase diff --git a/README.md b/README.md new file mode 100644 index 00000000..e69de29b diff --git a/angular.json b/angular.json new file mode 100644 index 00000000..eb9a6eef --- /dev/null +++ b/angular.json @@ -0,0 +1,110 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "axon": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss", + "skipTests": true + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:module": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/axon", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "aot": true, + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", + "src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb", + "maximumError": "10kb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "axon:build" + }, + "configurations": { + "production": { + "browserTarget": "axon:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "axon:build" + } + } + } + } + }, + "defaultProject": "axon", + "cli": { + "analytics": "df6da515-974d-42e6-89cd-f5660de09dce" + } +} \ No newline at end of file diff --git a/browserslist b/browserslist new file mode 100644 index 00000000..80848532 --- /dev/null +++ b/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..ce9eeaf5 --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "axon", + "version": "0.1.0", + "description": "Dashboard for delivering neuroscience experiments on the web for the Neurodegenration Research Laboratory at The Neuro (formerly Montreal Neurological Institute)", + "main": "src/main.ts", + "dependencies": { + "@angular/animations": "~9.1.2", + "@angular/cdk": "~9.2.1", + "@angular/common": "~9.1.2", + "@angular/compiler": "~9.1.2", + "@angular/core": "~9.1.2", + "@angular/forms": "~9.1.2", + "@angular/material": "^9.2.1", + "@angular/platform-browser": "~9.1.2", + "@angular/platform-browser-dynamic": "~9.1.2", + "@angular/router": "~9.1.2", + "rxjs": "~6.5.5", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.901.2", + "@angular/cli": "~9.1.2", + "@angular/compiler-cli": "~9.1.2", + "@angular/language-service": "~9.1.2", + "@types/node": "^12.11.1", + "ts-node": "~8.9.0", + "tslint": "~6.1.1", + "typescript": "~3.8.3" + }, + "scripts": { + "ng": "ng", + "start": "ng serve -o", + "build": "ng build --prod", + "lint": "ng lint" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cognitive-neuroscience/axon.git" + }, + "keywords": [ + "neuroscience" + ], + "author": "Praveen Ravichandran (me@pravinba9495.dev)", + "license": "ISC", + "bugs": { + "url": "https://github.com/cognitive-neuroscience/axon/issues" + }, + "homepage": "https://github.com/cognitive-neuroscience/axon#readme" +} \ No newline at end of file diff --git a/src/app/AppHttpInterceptor.ts b/src/app/AppHttpInterceptor.ts new file mode 100644 index 00000000..6843f372 --- /dev/null +++ b/src/app/AppHttpInterceptor.ts @@ -0,0 +1,43 @@ +import { + HttpErrorResponse, + HttpEvent, + HttpHandler, + HttpInterceptor, + HttpRequest +} from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { Router } from "@angular/router"; +import { Observable } from "rxjs"; +import { tap } from "rxjs/operators"; + +@Injectable() +export class AppHttpInterceptor implements HttpInterceptor { + + constructor(private router: Router) { } + + public intercept(request: HttpRequest, next: HttpHandler): Observable> { + if (localStorage.getItem('token')) { + request = request.clone({ + setHeaders: { + "Content-Type": "application/json", + "Authorization": "Bearer " + localStorage.getItem('token') + }, + }); + } else { + request = request.clone({ + setHeaders: { + "Content-Type": "application/json", + }, + }); + } + return next.handle(request).pipe(tap((event: HttpEvent) => { + }, (err: any) => { + if (err instanceof HttpErrorResponse) { + if ((err.status === 401) || (err.status === 403)) { + this.router.navigate(["/public/login"]); + localStorage.removeItem('token'); + } + } + })); + } +} \ No newline at end of file diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts new file mode 100644 index 00000000..afa283fd --- /dev/null +++ b/src/app/app-routing.module.ts @@ -0,0 +1,44 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { DashboardComponent } from './pages/dashboard/dashboard.component'; +import { LoginComponent } from './pages/login/login.component'; +import { ColorGameComponent } from './pages/experiments/color-game/color-game.component'; +import { ShapeGameComponent } from './pages/experiments/shape-game/shape-game.component'; +import { GoNogoComponent } from './pages/experiments/go-nogo/go-nogo.component'; +import { DigitSpanComponent } from './pages/experiments/digit-span/digit-span.component'; +import { TaskSwitchingComponent } from './pages/experiments/task-switching/task-switching.component'; +import { DemandSelectionComponent } from './pages/experiments/demand-selection/demand-selection.component'; +import { SimonTaskPrelimComponent } from './pages/experiments/simon-task-prelim/simon-task-prelim.component'; +import { SimonTaskFinalComponent } from './pages/experiments/simon-task-final/simon-task-final.component'; +import { SmileyFaceComponent } from './pages/experiments/smiley-face/smiley-face.component'; +import { FingerTappingTaskComponent } from './pages/experiments/finger-tapping-task/finger-tapping-task.component'; +import { NBackComponent } from './pages/experiments/n-back/n-back.component'; +import { StroopTaskComponent } from './pages/experiments/stroop-task/stroop-task.component'; +import { TrailMakingComponent } from './pages/experiments/trail-making/trail-making.component'; + + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'login', component: LoginComponent }, + { path: 'experiments/color-game', component: ColorGameComponent }, + { path: 'experiments/shape-game', component: ShapeGameComponent }, + { path: 'experiments/go-nogo', component: GoNogoComponent }, + { path: 'experiments/digit-span', component: DigitSpanComponent }, + { path: 'experiments/ts', component: TaskSwitchingComponent }, + { path: 'experiments/dst', component: DemandSelectionComponent }, + { path: 'experiments/simon-1', component: SimonTaskPrelimComponent }, + { path: 'experiments/simon-2', component: SimonTaskFinalComponent }, + { path: 'experiments/smiley-face', component: SmileyFaceComponent }, + { path: 'experiments/ftt', component: FingerTappingTaskComponent }, + { path: 'experiments/n-back', component: NBackComponent }, + { path: 'experiments/stroop', component: StroopTaskComponent }, + { path: 'experiments/trail-making', component: TrailMakingComponent }, + { path: '**', redirectTo: '/login', pathMatch: 'full' } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes, { useHash: true })], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/src/app/app.component.ts b/src/app/app.component.ts new file mode 100644 index 00000000..52589f4b --- /dev/null +++ b/src/app/app.component.ts @@ -0,0 +1,17 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-root', + template: ``, + styles: [] +}) +export class AppComponent implements OnInit { + + constructor(private router: Router) { } + + ngOnInit() { + this.router.navigate(['/dashboard']); + } + +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 00000000..202e9de9 --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,64 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { LoginComponent } from './pages/login/login.component'; +import { DashboardComponent } from './pages/dashboard/dashboard.component'; +import { ColorGameComponent } from './pages/experiments/color-game/color-game.component'; +import { ShapeGameComponent } from './pages/experiments/shape-game/shape-game.component'; +import { GoNogoComponent } from './pages/experiments/go-nogo/go-nogo.component'; +import { DigitSpanComponent } from './pages/experiments/digit-span/digit-span.component'; +import { DemandSelectionComponent } from './pages/experiments/demand-selection/demand-selection.component'; +import { TaskSwitchingComponent } from './pages/experiments/task-switching/task-switching.component'; +import { SimonTaskPrelimComponent } from './pages/experiments/simon-task-prelim/simon-task-prelim.component'; +import { SimonTaskFinalComponent } from './pages/experiments/simon-task-final/simon-task-final.component'; +import { ConsentComponent } from './pages/consent/consent.component'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { FormsModule } from '@angular/forms'; +import { MaterialModule } from './modules/material/material.module'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { AppHttpInterceptor } from './AppHttpInterceptor'; +import { FingerTappingTaskComponent } from './pages/experiments/finger-tapping-task/finger-tapping-task.component'; +import { NBackComponent } from './pages/experiments/n-back/n-back.component'; +import { StroopTaskComponent } from './pages/experiments/stroop-task/stroop-task.component'; +import { SmileyFaceComponent } from './pages/experiments/smiley-face/smiley-face.component'; +import { TrailMakingComponent } from './pages/experiments/trail-making/trail-making.component'; + +@NgModule({ + declarations: [ + AppComponent, + LoginComponent, + DashboardComponent, + ColorGameComponent, + ShapeGameComponent, + GoNogoComponent, + DigitSpanComponent, + DemandSelectionComponent, + TaskSwitchingComponent, + SimonTaskPrelimComponent, + SimonTaskFinalComponent, + ConsentComponent, + FingerTappingTaskComponent, + NBackComponent, + StroopTaskComponent, + SmileyFaceComponent, + TrailMakingComponent + ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + FormsModule, + MaterialModule, + HttpClientModule + ], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: AppHttpInterceptor, + multi: true, + } + ], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/src/app/models/Experiment.ts b/src/app/models/Experiment.ts new file mode 100644 index 00000000..bb0633a3 --- /dev/null +++ b/src/app/models/Experiment.ts @@ -0,0 +1,16 @@ +export class Experiment { + id: number = 0; + title: string = ''; + description: string = ''; + route: string = ''; + type: string = ''; + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 0; + maxResponseTime: number = 800; + durationOfFeedback: number = 1000; + interTrialDelay: number = 1000; + practiceTrials: number = 1; + actualTrials: number = 10; +} diff --git a/src/app/models/LoginCredentials.ts b/src/app/models/LoginCredentials.ts new file mode 100644 index 00000000..889c377d --- /dev/null +++ b/src/app/models/LoginCredentials.ts @@ -0,0 +1,4 @@ +export class LoginCredentials { + email: string = ''; + password: string = ''; +} diff --git a/src/app/models/LoginResponse.ts b/src/app/models/LoginResponse.ts new file mode 100644 index 00000000..530d1a4a --- /dev/null +++ b/src/app/models/LoginResponse.ts @@ -0,0 +1,6 @@ +export class LoginResponse { + message: string = ''; + status: number = 0; + token: string = ''; + role: string = ''; +} diff --git a/src/app/modules/material/material.module.ts b/src/app/modules/material/material.module.ts new file mode 100644 index 00000000..d1679344 --- /dev/null +++ b/src/app/modules/material/material.module.ts @@ -0,0 +1,45 @@ +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatTableModule } from '@angular/material/table'; +import { MatCardModule } from '@angular/material/card'; + +const modules = [ + MatInputModule, + MatFormFieldModule, + MatButtonModule, + MatDialogModule, + MatProgressSpinnerModule, + MatIconModule, + MatSelectModule, + MatCheckboxModule, + MatRadioModule, + DragDropModule, + MatSnackBarModule, + MatToolbarModule, + MatTableModule, + MatCardModule +]; + +@NgModule({ + declarations: [], + imports: [ + CommonModule, + modules + ], + exports: [ + modules + ] +}) +export class MaterialModule { } diff --git a/src/app/pages/consent/consent.component.html b/src/app/pages/consent/consent.component.html new file mode 100644 index 00000000..f28b6f42 --- /dev/null +++ b/src/app/pages/consent/consent.component.html @@ -0,0 +1,192 @@ +
+ +

+ CONSENT +

+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et + dolore + magna + aliqua. Purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Adipiscing commodo elit at + imperdiet + dui + accumsan. Arcu dictum varius duis at consectetur lorem donec massa sapien. Consectetur adipiscing elit + pellentesque + habitant. Ultricies tristique nulla aliquet enim tortor at auctor urna. A scelerisque purus semper eget duis + at + tellus. + Ultrices in iaculis nunc sed augue lacus. Elementum facilisis leo vel fringilla. Nibh nisl condimentum id + venenatis a. +

+ +

+ Condimentum lacinia quis vel eros donec ac odio. Justo nec ultrices dui sapien eget mi. Tristique senectus + et + netus et. + Sed cras ornare arcu dui vivamus arcu felis. Vitae suscipit tellus mauris a diam maecenas sed enim. Mauris + pharetra et + ultrices neque ornare aenean euismod elementum. Urna nec tincidunt praesent semper. Rhoncus urna neque + viverra + justo. + Malesuada fames ac turpis egestas maecenas pharetra convallis. Fermentum odio eu feugiat pretium nibh ipsum + consequat + nisl. Neque sodales ut etiam sit. In pellentesque massa placerat duis ultricies. Massa ultricies mi quis + hendrerit dolor + magna eget. Sodales ut eu sem integer vitae justo. Aliquet nec ullamcorper sit amet risus nullam eget. Vitae + ultricies + leo integer malesuada. Nulla pharetra diam sit amet nisl. +

+ +

+ Imperdiet proin fermentum leo vel orci porta. Magnis dis parturient montes nascetur. Ultricies tristique + nulla + aliquet + enim tortor at auctor urna. Velit aliquet sagittis id consectetur purus ut. Id diam maecenas ultricies mi + eget + mauris. + Quis eleifend quam adipiscing vitae proin. Sit amet mattis vulputate enim nulla aliquet porttitor lacus + luctus. + Egestas + congue quisque egestas diam in arcu. Lacus vestibulum sed arcu non odio euismod lacinia. Amet mattis + vulputate + enim + nulla aliquet porttitor lacus luctus accumsan. Leo integer malesuada nunc vel risus commodo viverra. Cras + fermentum odio + eu feugiat pretium. Dolor magna eget est lorem ipsum dolor sit amet consectetur. +

+ +

+ Arcu odio ut sem nulla pharetra diam sit amet nisl. Velit dignissim sodales ut eu sem integer vitae justo. + Adipiscing + vitae proin sagittis nisl rhoncus mattis. Mollis nunc sed id semper risus in hendrerit gravida rutrum. Vitae + congue + mauris rhoncus aenean. Euismod in pellentesque massa placerat duis. Enim praesent elementum facilisis leo + vel + fringilla + est ullamcorper. Arcu dictum varius duis at consectetur lorem donec. Penatibus et magnis dis parturient. + Dignissim enim + sit amet venenatis urna cursus. Vitae semper quis lectus nulla at volutpat. +

+ +

+ Amet justo donec enim diam vulputate ut pharetra. Convallis a cras semper auctor neque vitae tempus quam + pellentesque. + Ultrices neque ornare aenean euismod elementum. Amet massa vitae tortor condimentum lacinia quis vel eros + donec. + Viverra + aliquet eget sit amet tellus. Adipiscing elit ut aliquam purus. Egestas pretium aenean pharetra magna ac + placerat + vestibulum. Libero volutpat sed cras ornare arcu. Et magnis dis parturient montes nascetur ridiculus mus + mauris. + Feugiat + pretium nibh ipsum consequat nisl vel pretium. Dictum fusce ut placerat orci nulla. Laoreet suspendisse + interdum + consectetur libero id faucibus nisl tincidunt. +

+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et + dolore + magna + aliqua. Purus viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Adipiscing commodo elit at + imperdiet + dui + accumsan. Arcu dictum varius duis at consectetur lorem donec massa sapien. Consectetur adipiscing elit + pellentesque + habitant. Ultricies tristique nulla aliquet enim tortor at auctor urna. A scelerisque purus semper eget duis + at + tellus. + Ultrices in iaculis nunc sed augue lacus. Elementum facilisis leo vel fringilla. Nibh nisl condimentum id + venenatis a. +

+ +

+ Condimentum lacinia quis vel eros donec ac odio. Justo nec ultrices dui sapien eget mi. Tristique senectus + et + netus et. + Sed cras ornare arcu dui vivamus arcu felis. Vitae suscipit tellus mauris a diam maecenas sed enim. Mauris + pharetra et + ultrices neque ornare aenean euismod elementum. Urna nec tincidunt praesent semper. Rhoncus urna neque + viverra + justo. + Malesuada fames ac turpis egestas maecenas pharetra convallis. Fermentum odio eu feugiat pretium nibh ipsum + consequat + nisl. Neque sodales ut etiam sit. In pellentesque massa placerat duis ultricies. Massa ultricies mi quis + hendrerit dolor + magna eget. Sodales ut eu sem integer vitae justo. Aliquet nec ullamcorper sit amet risus nullam eget. Vitae + ultricies + leo integer malesuada. Nulla pharetra diam sit amet nisl. +

+ +

+ Imperdiet proin fermentum leo vel orci porta. Magnis dis parturient montes nascetur. Ultricies tristique + nulla + aliquet + enim tortor at auctor urna. Velit aliquet sagittis id consectetur purus ut. Id diam maecenas ultricies mi + eget + mauris. + Quis eleifend quam adipiscing vitae proin. Sit amet mattis vulputate enim nulla aliquet porttitor lacus + luctus. + Egestas + congue quisque egestas diam in arcu. Lacus vestibulum sed arcu non odio euismod lacinia. Amet mattis + vulputate + enim + nulla aliquet porttitor lacus luctus accumsan. Leo integer malesuada nunc vel risus commodo viverra. Cras + fermentum odio + eu feugiat pretium. Dolor magna eget est lorem ipsum dolor sit amet consectetur. +

+ +

+ Arcu odio ut sem nulla pharetra diam sit amet nisl. Velit dignissim sodales ut eu sem integer vitae justo. + Adipiscing + vitae proin sagittis nisl rhoncus mattis. Mollis nunc sed id semper risus in hendrerit gravida rutrum. Vitae + congue + mauris rhoncus aenean. Euismod in pellentesque massa placerat duis. Enim praesent elementum facilisis leo + vel + fringilla + est ullamcorper. Arcu dictum varius duis at consectetur lorem donec. Penatibus et magnis dis parturient. + Dignissim enim + sit amet venenatis urna cursus. Vitae semper quis lectus nulla at volutpat. +

+ +

+ Amet justo donec enim diam vulputate ut pharetra. Convallis a cras semper auctor neque vitae tempus quam + pellentesque. + Ultrices neque ornare aenean euismod elementum. Amet massa vitae tortor condimentum lacinia quis vel eros + donec. + Viverra + aliquet eget sit amet tellus. Adipiscing elit ut aliquam purus. Egestas pretium aenean pharetra magna ac + placerat + vestibulum. Libero volutpat sed cras ornare arcu. Et magnis dis parturient montes nascetur ridiculus mus + mauris. + Feugiat + pretium nibh ipsum consequat nisl vel pretium. Dictum fusce ut placerat orci nulla. Laoreet suspendisse + interdum + consectetur libero id faucibus nisl tincidunt. +

+ +
+
+
+ +
+
+ +
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/consent/consent.component.scss b/src/app/pages/consent/consent.component.scss new file mode 100644 index 00000000..e7fdbeb0 --- /dev/null +++ b/src/app/pages/consent/consent.component.scss @@ -0,0 +1,4 @@ +.mat-h1{ + padding: 20px; + font-weight: 500; +} \ No newline at end of file diff --git a/src/app/pages/consent/consent.component.ts b/src/app/pages/consent/consent.component.ts new file mode 100644 index 00000000..1cbf74ca --- /dev/null +++ b/src/app/pages/consent/consent.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit, EventEmitter, Output } from '@angular/core'; + +@Component({ + selector: 'app-consent', + templateUrl: './consent.component.html', + styleUrls: ['./consent.component.scss'] +}) +export class ConsentComponent implements OnInit { + + @Output() + broadcastConsent: EventEmitter = new EventEmitter(); + + constructor() { } + + ngOnInit() { + } + + consent(answer: boolean) { + this.broadcastConsent.emit(answer); + } + +} diff --git a/src/app/pages/dashboard/dashboard.component.html b/src/app/pages/dashboard/dashboard.component.html new file mode 100644 index 00000000..3b42dea3 --- /dev/null +++ b/src/app/pages/dashboard/dashboard.component.html @@ -0,0 +1,75 @@ + + Dashboard + + + + +
+

+ Neuropsych Battery +

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + +
Title {{task.title}} Description {{task.description}} Actions
+
+ +
+ +
+

+ Experimental Tasks +

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + +
Title {{experiment.title}} Description {{experiment.description}} Actions
+
+
\ No newline at end of file diff --git a/src/app/pages/dashboard/dashboard.component.scss b/src/app/pages/dashboard/dashboard.component.scss new file mode 100644 index 00000000..2fedae5a --- /dev/null +++ b/src/app/pages/dashboard/dashboard.component.scss @@ -0,0 +1,7 @@ +.title{ + font-weight: 300; +} + +table { + width: 100%; +} \ No newline at end of file diff --git a/src/app/pages/dashboard/dashboard.component.ts b/src/app/pages/dashboard/dashboard.component.ts new file mode 100644 index 00000000..34c766de --- /dev/null +++ b/src/app/pages/dashboard/dashboard.component.ts @@ -0,0 +1,59 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Experiment } from 'src/app/models/Experiment'; +import { DataService } from 'src/app/services/data.service'; +import { Subscription } from 'rxjs'; +import { Router } from '@angular/router'; +declare function closeFullscreen(): any; +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: ['./dashboard.component.scss'] +}) +export class DashboardComponent implements OnInit, OnDestroy { + + tasks: Experiment[] = []; + experiments: Experiment[] = []; + displayedColumnsForExperiments: string[] = ['title', 'description', 'route']; + displayedColumnsForOthers: string[] = ['title', 'description', 'data']; + experimentsSubscription: Subscription = new Subscription(); + questionnairesSubscription: Subscription = new Subscription(); + workflowsSubscription: Subscription = new Subscription(); + + constructor( + private dataService: DataService, + private router: Router + ) { } + + async ngOnInit() { + + try { + await closeFullscreen(); + } catch (error) { + + } + + this.experimentsSubscription = this.dataService.getExperiments().subscribe((results: Experiment[]) => { + this.dataService.setExperiments(results); + this.tasks = results.filter(result => result.type === 'task').sort((a, b) => { + if (a.id > b.id) return 1; else return -1; + }); + this.experiments = results.filter(result => result.type === 'experiment').sort((a, b) => { + if (a.id > b.id) return 1; else return -1; + });; + }, (error) => { + console.error(error); + }); + + } + + ngOnDestroy() { + this.experimentsSubscription.unsubscribe(); + this.questionnairesSubscription.unsubscribe(); + this.workflowsSubscription.unsubscribe(); + } + + run(prefix: string, path: string) { + this.router.navigate([`/${prefix}/${path}`]); + } + +} diff --git a/src/app/pages/experiments/color-game/color-game.component.html b/src/app/pages/experiments/color-game/color-game.component.html new file mode 100644 index 00000000..9e361e66 --- /dev/null +++ b/src/app/pages/experiments/color-game/color-game.component.html @@ -0,0 +1,494 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Color Game

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ You will be shown 6 circles on the screen +
+ +
+ Your job is to find the RED or GREEN circle and tell us if the bar inside the circle is horizontal + or + vertical. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+

+

+
+ +
+ For instance, here the circle has a horizontal bar: +
+ +
+ Press the Z key if the bar is horizontal. +
+ +
+ Press the M key if the bar is vertical. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Remember, +
+ Press the Z key if the bar is horizontal. +
+ Press the M key if the bar is vertical. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn between 1-10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, +
+ Press the Z key if the bar is horizontal. +
+ Press the M key if the bar is vertical. +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/color-game/color-game.component.scss b/src/app/pages/experiments/color-game/color-game.component.scss new file mode 100644 index 00000000..0769ceab --- /dev/null +++ b/src/app/pages/experiments/color-game/color-game.component.scss @@ -0,0 +1,28 @@ + +table{ + td{ + width: 120px; + height: 100px; + text-align: center; + div{ + display: inline-block; + } + .line{ + position: fixed; + height: 10px; + width: 55px; + margin-top: 32.5px; + margin-left: 10.5px; + background-color: black; + } + .m{ + transform: rotate(90deg); + } + .s{ + transform: rotate(45deg); + } + .z{ + transform: rotate(0deg); + } + } +} \ No newline at end of file diff --git a/src/app/pages/experiments/color-game/color-game.component.ts b/src/app/pages/experiments/color-game/color-game.component.ts new file mode 100644 index 00000000..7c727d75 --- /dev/null +++ b/src/app/pages/experiments/color-game/color-game.component.ts @@ -0,0 +1,400 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-color-game', + templateUrl: './color-game.component.html', + styleUrls: ['./color-game.component.scss'] +}) +export class ColorGameComponent implements OnInit { + + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 0; + maxResponseTime: number = 800; + durationOfFeedback: number = 500; + interTrialDelay: number = 1000; + practiceTrials: number = 10; + actualTrials: number = 30; + step: number = 1; + color: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: any[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + colors = []; + c = { + a: '', + b: '', + c: '', + d: '', + e: '', + f: '' + }; + + a = { + a: 's', + b: 's', + c: 's', + d: 's', + e: 's', + f: 's' + }; + + colors_all = [ + 'blue', + 'orange', + 'brown', + 'grey', + 'purple' + ]; + + trial_reward_probs = []; + trial_colors = []; + + + @HostListener('window:keydown', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (event.key === 'z' || event.key === 'm') { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (!!event.key) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + switch (event.key) { + case 'z': this.data[this.data.length - 1].userAnswer = 'Z'; break; + case 'm': this.data[this.data.length - 1].userAnswer = 'M'; break; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.calculateProbs(); + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.calculateProbs(); + this.showStimulus(); + } + + + calculateProbs() { + let trials_max = 30; + if (this.isPractice) { + trials_max = this.practiceTrials; + } else { + trials_max = this.actualTrials; + } + this.trial_reward_probs = []; + this.trial_colors = []; + for (let i = 0; i < trials_max; i++) { + if (i < (trials_max / 2)) { + this.trial_colors.push('red'); + this.trial_reward_probs.push(0.1); + } else { + this.trial_colors.push('teal'); + this.trial_reward_probs.push(0.9); + } + } + this.trial_colors = this.shuffle(this.trial_colors); + this.trial_reward_probs = this.shuffle(this.trial_reward_probs); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + generateStimulus() { + const color = this.trial_colors[this.currentTrial]; + this.colors = this.colors_all.concat(color); + this.colors = this.shuffle(this.colors); + this.c.a = this.colors[0]; + this.c.b = this.colors[1]; + this.c.c = this.colors[2]; + this.c.d = this.colors[3]; + this.c.e = this.colors[4]; + this.c.f = this.colors[5]; + const align = (Math.floor(Math.random() * 2) + 1) === 1 ? 'm' : 'z'; + this.a.a = ((this.c.a === 'red') || (this.c.a === 'teal')) ? align : 's'; + this.a.b = ((this.c.b === 'red') || (this.c.b === 'teal')) ? align : 's'; + this.a.c = ((this.c.c === 'red') || (this.c.c === 'teal')) ? align : 's'; + this.a.d = ((this.c.d === 'red') || (this.c.d === 'teal')) ? align : 's'; + this.a.e = ((this.c.e === 'red') || (this.c.e === 'teal')) ? align : 's'; + this.a.f = ((this.c.f === 'red') || (this.c.f === 'teal')) ? align : 's'; + this.data.push({ + targetColor: color, + targetLocation: this.colors.indexOf(color) + 1, + targetAlignment: (align === 'z' ? 'horizantal' : 'vertical').toUpperCase(), + actualAnswer: align.toUpperCase(), + userAnswer: '', + probability: 0, + random: 0, + responseTime: 0, + isCorrect: 0, + score: 0 + }); + } + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + let rand = Math.random(); + let points = rand <= this.trial_reward_probs[this.currentTrial] ? 10 : 1; + this.data[this.data.length - 1].probability = this.trial_reward_probs[this.currentTrial]; + this.data[this.data.length - 1].random = rand; + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = points; + this.scoreForSpecificTrial = points; + this.totalScore += points; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + + + shuffle(a) { + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; + } + + +} diff --git a/src/app/pages/experiments/demand-selection/demand-selection.component.html b/src/app/pages/experiments/demand-selection/demand-selection.component.html new file mode 100644 index 00000000..4ecde594 --- /dev/null +++ b/src/app/pages/experiments/demand-selection/demand-selection.component.html @@ -0,0 +1,495 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Patch Game

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ Now you will be playing a slightly different game. +
+ +
+ Your goal is still to make a decision about the number on the screen based on its color, BLUE or + GREEN. +
+ +
+ However, here you will see two patches on the screen and will have to pick one. +
+ + +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+

More Instructions

+
+ + +
+ +
+

+

+
+ +
+ Each patch is hiding a colored number. +
+ +
+ There are differences between the patches. +
+ +
+ One patch is hiding numbers that change color less often. +
+ +
+ Other patch is hiding numbers that change color more often. +
+ + +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+

More Instructions

+
+ + +
+ +
+ If you develop a preference for one of the patches, feel free to continue to choose it. +
+ +
+ However, we recommend that you try both patches at the beginning. +
+ +
+ Try to avoid choosing the patch solely based on how they look or on their location. +
+ +
+ You must always start in the starting position, with the cursor on the middle dot. +
+ + +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+

More Instructions

+
+ + +
+ +
+ To select a patch, move the mouse cursor over to it. +
+ +
+ As soon as you hover over it, the colored number will appear. +
+ +
+ Then use the mouse buttons as before to give us your answer. +
+ + +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{number}} +
+ +
+ add +
+ +
+
+ +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ This time we will not give you feedback after each answer. +
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{number}} +
+ +
+ add +
+ +
+
+ +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/demand-selection/demand-selection.component.scss b/src/app/pages/experiments/demand-selection/demand-selection.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/demand-selection/demand-selection.component.ts b/src/app/pages/experiments/demand-selection/demand-selection.component.ts new file mode 100644 index 00000000..3ecdbfce --- /dev/null +++ b/src/app/pages/experiments/demand-selection/demand-selection.component.ts @@ -0,0 +1,401 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; +import { Matrix } from './matrix'; + +@Component({ + selector: 'app-demand-selection', + templateUrl: './demand-selection.component.html', + styleUrls: ['./demand-selection.component.scss'] +}) +export class DemandSelectionComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 2; + maxResponseTime: number = 800; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 10; + actualTrials: number = 30; + showPatches: boolean = false; + showNumber: boolean = false; + step: number = 1; + color: string = 'transparent'; + number: number = 0; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + color: string, + digit: number, + actualAnswer: string, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + matrix = new Matrix(); + + @HostListener('document:click', ['$event']) + onKeyPress(event: MouseEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (this.data[this.data.length - 1].color === 'blue') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'LESSER'; + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'ODD'; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } catch (error) { + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + processClickEvent(event: any) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (this.data[this.data.length - 1].color === 'blue') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'GREATER'; + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'EVEN'; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } catch (error) { + } + } + event.preventDefault(); + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.showFeedbackAfterEveryTrial = false; + this.showScoreAfterEveryTrial = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + this.showNumber = false; + this.showPatches = false; + await this.wait(200); + + this.currentTrial += 1; + this.isStimulus = true; + } + + + onHoverCursor(event) { + this.showPatches = true; + this.showFixation = false; + this.showNumber = false; + this.isResponseAllowed = false; + this.timer.started = 0; + this.timer.ended = 0; + } + + onHoverPatch(event, side = 'left') { + let rand = 0; + if (side === 'left') { + rand = this.matrix.colors[this.currentTrial - 1]; + } else { + rand = this.matrix.colors2[this.currentTrial - 1]; + } + + let color = 'blue'; + if (rand === 1) { + color = 'blue'; + } else { + color = 'green'; + } + const digit = this.matrix.digits[this.currentTrial - 1]; + let answer = ''; + if (color === 'green') { + if (digit % 2 === 0) { + answer = 'EVEN'; + } else { + answer = 'ODD'; + } + } else { + if (digit > 5) { + answer = 'GREATER'; + } else { + answer = 'LESSER'; + } + } + + this.color = color; + this.number = digit; + + this.data.push({ + color: color, + digit: digit, + actualAnswer: answer, + userAnswer: '', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + + this.showPatches = false; + this.showFixation = false; + this.showNumber = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + + } + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.showPatches = false; + this.showFixation = false; + this.showNumber = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.number = 0; + this.color = 'transparent'; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + this.showPatches = false; + this.showFixation = false; + this.showNumber = false; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/demand-selection/matrix.ts b/src/app/pages/experiments/demand-selection/matrix.ts new file mode 100644 index 00000000..785bca83 --- /dev/null +++ b/src/app/pages/experiments/demand-selection/matrix.ts @@ -0,0 +1,13 @@ +export class Matrix { + colors: number[] = [ + 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1 + ]; + + colors2: number[] = [ + 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2 + ]; + + digits: number[] = [ + 4, 7, 6, 9, 6, 4, 1, 8, 7, 3, 2, 4, 7, 3, 4, 8, 2, 4, 1, 2, 6, 7, 2, 9, 3, 6, 3, 2, 9, 2, 1, 9, 1, 7, 8, 6, 1, 8, 7, 3, 9, 4, 9, 1, 7, 4, 2, 4, 7, 8, 7, 1, 2, 6, 1, 2, 9, 3, 7, 2, 9, 1, 2, 1, 3, 1, 2, 7, 8, 9, 8, 2, 9, 4, 1, 6, 7, 3, 9, 7, 6, 4, 8, 6, 4, 8, 7, 6, 4, 7, 9, 4, 6, 2, 8, 1, 7, 3, 8, 2, 8, 1, 6, 7, 4, 1, 6, 1, 3, 8, 7, 6, 2, 7, 4, 2, 8, 3, 2, 1, 3, 8, 9, 4, 8 + ]; +} \ No newline at end of file diff --git a/src/app/pages/experiments/digit-span/digit-span.component.html b/src/app/pages/experiments/digit-span/digit-span.component.html new file mode 100644 index 00000000..55ffd615 --- /dev/null +++ b/src/app/pages/experiments/digit-span/digit-span.component.html @@ -0,0 +1,450 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Digit Span Task

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, a sequence of numbers will appear on the screen, one at a time +
+ +
+ When the keypad is shown, you need to enter the numbers in the same order and click the next arrow +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Remember, when the keypad is shown, you need to enter the numbers in the same order as they were shown + and click the next arrow +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{digitShown}} +
+
+ +
+ add +
+ +
+ +
+ +
+
+ +
+
+
+ 1 +
+
+ 2 +
+
+ 3 +
+
+
+
+ 4 +
+
+ 5 +
+
+ 6 +
+
+
+
+ 7 +
+
+ 8 +
+
+ 9 +
+
+
+
+ clear +
+
+ 0 +
+
+ play_arrow +
+
+
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, when the keypad is shown, you need to enter the numbers in the same order as they were shown + and click the next arrow +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+
+
+ {{digitShown}} +
+
+ +
+ add +
+ +
+ +
+ +
+
+ +
+
+
+ 1 +
+
+ 2 +
+
+ 3 +
+
+
+
+ 4 +
+
+ 5 +
+
+ 6 +
+
+
+
+ 7 +
+
+ 8 +
+
+ 9 +
+
+
+
+ clear +
+
+ 0 +
+
+ play_arrow +
+
+
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/experiments/digit-span/digit-span.component.scss b/src/app/pages/experiments/digit-span/digit-span.component.scss new file mode 100644 index 00000000..bb652e95 --- /dev/null +++ b/src/app/pages/experiments/digit-span/digit-span.component.scss @@ -0,0 +1,17 @@ +.keypadButton{ + border-radius: 5px; + background: black; + color: white; + font-size: 30px; + margin: 5px; + width: 100px; + padding-top: 30px; + padding-bottom: 30px; + text-align: center; + border: solid thin black; + cursor: pointer; + &:hover{ + background: white; + color: black; + } +} \ No newline at end of file diff --git a/src/app/pages/experiments/digit-span/digit-span.component.ts b/src/app/pages/experiments/digit-span/digit-span.component.ts new file mode 100644 index 00000000..e7a029bd --- /dev/null +++ b/src/app/pages/experiments/digit-span/digit-span.component.ts @@ -0,0 +1,356 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-digit-span', + templateUrl: './digit-span.component.html', + styleUrls: ['./digit-span.component.scss'] +}) +export class DigitSpanComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = false; + showScoreAfterEveryTrial: boolean | number = false; + numberOfBreaks: number = 0; + maxResponseTime: number = 0; // In milliseconds, 0 for indefinte + durationOfFeedback: number = 1000; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 1; + actualTrials: number = 6; + + step: number = 1; + digitShown: string = ''; + textShown: string = ''; + userAnswer: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isKeypad: boolean = false; + isFeedback: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + + accuracy: number = 0; + failedAttempts: number = 0; + correctAttempts: number = 0; + numberLen: number = 3; + + data: { + actualAnswer: string, + userAnswer: string, + responseTime: number, + numberOfDigits: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + + this.isStimulus = true; + this.isKeypad = false; + this.isFeedback = false; + + this.generateStimulus().then(async () => { + this.data.push({ + userAnswer: '', + actualAnswer: this.textShown, + responseTime: 0, + numberOfDigits: this.textShown.length, + isCorrect: 0, + score: 0 + }); + this.isStimulus = false; + this.isKeypad = true; + this.isResponseAllowed = true; + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + }) + } + + + + generateStimulus() { + if (this.failedAttempts >= 3) { + this.numberLen -= 1; + this.failedAttempts = 0; + this.correctAttempts = 0; + } + if (this.correctAttempts >= 3) { + this.numberLen += 1; + this.correctAttempts = 0; + } + if (this.numberLen < 3) { + this.numberLen = 3; + } + if (this.numberLen > 7) { + this.numberLen = 7; + } + let min = this.getMaxMin(this.numberLen).min; + let max = this.getMaxMin(this.numberLen).max; + let numberToShow = Math.floor(Math.random() * (max - min + 1)) + min; + let numAsArray = numberToShow.toString().split('').join('_').split(''); + this.userAnswer = ''; + this.textShown = numberToShow.toString(); + console.log(this.textShown, numAsArray); + let promise = Promise.resolve(); + numAsArray.forEach((digit) => { + promise = promise.then(() => { + this.digitShown = digit === '_' ? '' : digit; + return new Promise((resolve) => { + setTimeout(resolve, digit === '_' ? 300 : 1000); + }); + }); + }); + return promise; + } + + + getMaxMin(len: number) { + let ret = { + min: 100, + max: 999 + }; + switch (len) { + case 4: ret.min = 1000; ret.max = 9999; break; + case 5: ret.min = 10000; ret.max = 99999; break; + case 6: ret.min = 100000; ret.max = 999999; break; + case 7: ret.min = 1000000; ret.max = 9999999; break; + } + return ret; + } + + + + addNumber(num: number) { + this.userAnswer += num.toString(); + } + + + + async showFeedback() { + this.data[this.data.length - 1].userAnswer = this.userAnswer; + this.isStimulus = false; + this.isKeypad = false; + this.isFeedback = true; + this.isResponseAllowed = false; + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + console.log() + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + this.correctAttempts += 1; + this.failedAttempts = 0; + } else { + this.feedback = "Incorrect"; + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + this.correctAttempts = 0; + this.failedAttempts += 1; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.textShown = ''; + this.feedback = ''; + this.textShown = ''; + this.digitShown = ''; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + this.accuracy = 0; + this.numberLen = 3; + this.correctAttempts = 0; + this.failedAttempts = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.html b/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.html new file mode 100644 index 00000000..e76bd819 --- /dev/null +++ b/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.html @@ -0,0 +1,410 @@ +
+ +
+ +
+ + +
+ + +
+

Welcome to Finger Tapping Task

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ You will be asked to alternately tap two keys on the keyboard as fast as you can. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ + +
+
+ + +
+ + +
+ You will do this by using your index finger. +
+ +
+ This means that you will have to tap each key one after the other by alternating back and forth. +
+ +
+ You will be told which hand you should use just before you start. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ + +
+
+ + +
+ + +
+ The keys you will be tapping on the keyboard are the '{{keyA}}' and the '{{keyB}}' keys. +
+ +
+ Please go ahead and find these keys now. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+
+ + +
+ + +
+ Each tapping test will last 1 minute. This means that for one full minute, you have to keep tapping as + fast as you can. +
+ +
+ In total you will do 6 tests: 3 with each index finger. +
+ +
+ This may seem long, but you will be given breaks between each test. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ + +
+
+ + +
+ + +
+ Please use your {{hand === 'L' ? 'LEFT' : 'RIGHT'}} hand. +
+ +
+ Remember: +
+ Tap the '{{keyA}}' and the '{{keyB}}' keys as fast as you can. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
{{time2}}
+
+ +
+ + +
+ +
+

Begin Tapping

+
+ +
+
+ add +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ {{time}} seconds +
+ +
+ It's break time +
+ +
+ A minimum break of 30 seconds is required before you proceed to the next block. +
+ +
+ The game will resume automatically in 120 seconds (2 minutes). +
+
+ + + +
+
+
+ +
+
+ +
+
+
+ +
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.scss b/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.ts b/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.ts new file mode 100644 index 00000000..e9f19bb2 --- /dev/null +++ b/src/app/pages/experiments/finger-tapping-task/finger-tapping-task.component.ts @@ -0,0 +1,236 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; + +declare function setFullScreen(): any; + +@Component({ + selector: 'app-finger-tapping-task', + templateUrl: './finger-tapping-task.component.html', + styleUrls: ['./finger-tapping-task.component.scss'] +}) +export class FingerTappingTaskComponent implements OnInit { + + isBreak: boolean = false; + step: number = 1; + isScored: number | boolean; + showFeedbackAfterEveryTrial: number | boolean; + showScoreAfterEveryTrial: number | boolean; + numberOfBreaks: number; + maxResponseTime: number; + durationOfFeedback: number; + interTrialDelay: number; + practiceTrials: number; + actualTrials: number; + keyA: string; + keyB: string; + block: number = 0; + gameOn: boolean; + blockTimer; + hand: string; + showFixation: boolean = false; + lastKey: string; + currentTrial: number = 1; + startTime: number; + data: { + hand: string, + block: number, + key: string, + responseTime: number + }[] = []; + fixationTimeout; + time: number; + breakTimer; + resumeDisabled: boolean = false; + countdownTimer; + time2: number; + + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.gameOn) { + if ([this.keyA, this.keyB].includes(event.key.toUpperCase())) { + if (event.key.toUpperCase() !== this.lastKey) { + this.showFixation = true; + this.fixationTimeout = setTimeout(() => { + this.showFixation = false; + }, 50); + this.data.push({ + hand: this.hand, + block: this.block, + key: event.key.toUpperCase(), + responseTime: new Date().getTime() - this.startTime + }); + this.currentTrial += 1; + this.startTime = new Date().getTime(); + this.lastKey = event.key.toUpperCase(); + } + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored; + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial; + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial; + this.numberOfBreaks = currentExperiment.numberOfBreaks; + this.maxResponseTime = currentExperiment.maxResponseTime; + this.durationOfFeedback = currentExperiment.durationOfFeedback; + this.interTrialDelay = currentExperiment.interTrialDelay; + this.practiceTrials = currentExperiment.practiceTrials; + this.actualTrials = currentExperiment.actualTrials; + if (Math.random() > 0.5) { + this.keyA = 'Q'; + this.keyB = 'P'; + } else { + this.keyA = '1'; + this.keyB = '-'; + } + this.lastKey = this.keyB; + this.hand = Math.random() > 0.5 ? 'L' : 'R'; + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + startCountDownTimer() { + this.startGameInFullScreen(); + this.proceedtoNextStep(); + this.time2 = 5; + this.countdownTimer = setInterval(() => { + this.time2 -= 1; + if (this.time2 === 0) { + try { + clearInterval(this.countdownTimer); + } catch (error) { + + } + this.startBlock(); + } + }, 1000); + } + + + startBlock() { + this.lastKey = this.keyB; + this.proceedtoNextStep(); + this.block += 1; + this.startBlockTimer(); + } + + startBlockTimer() { + this.isBreak = false; + this.gameOn = true; + this.startTime = new Date().getTime(); + this.blockTimer = setTimeout(() => { + this.stopBlockTimer(); + }, 60000); + } + + async stopBlockTimer() { + this.gameOn = false; + try { + clearTimeout(this.blockTimer); + } catch (error) { + + } + this.isBreak = true; + this.proceedtoNextStep(); + if (this.block < 6) { + this.startBreakTimer(); + this.hand = this.hand === 'L' ? 'R' : 'L'; + } else { + this.isBreak = false; + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + + startBreakTimer() { + this.time = 0; + this.resumeDisabled = true; + this.breakTimer = setInterval(() => { + this.time += 1; + if (this.time === 30) { + this.resumeDisabled = false; + } + if (this.time === 120) { + try { + clearInterval(this.breakTimer); + } catch (error) { + + } + this.isBreak = false; + this.proceedtoNextStep(); + } + }, 1000); + } + + stopBreakTimer() { + try { + clearInterval(this.breakTimer); + } catch (error) { + + } + this.isBreak = false; + this.proceedtoNextStep(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/go-nogo/go-nogo.component.html b/src/app/pages/experiments/go-nogo/go-nogo.component.html new file mode 100644 index 00000000..8357de54 --- /dev/null +++ b/src/app/pages/experiments/go-nogo/go-nogo.component.html @@ -0,0 +1,358 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Go Nogo Task

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, you will be shown a square, either GREEN or + ORANGE +
+ +
+ Your goal is to press the spacebar if the square shown is in GREEN +
+ +
+ Do not respond if the square shown is in ORANGE +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Remember, press the spacebar if the square shown is in GREEN +
+ +
+ Do not respond if the square shown is in ORANGE +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, press the spacebar if the square shown is in GREEN +
+ +
+ Do not respond if the square shown is in ORANGE +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/experiments/go-nogo/go-nogo.component.scss b/src/app/pages/experiments/go-nogo/go-nogo.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/go-nogo/go-nogo.component.ts b/src/app/pages/experiments/go-nogo/go-nogo.component.ts new file mode 100644 index 00000000..6a99a647 --- /dev/null +++ b/src/app/pages/experiments/go-nogo/go-nogo.component.ts @@ -0,0 +1,327 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-go-nogo', + templateUrl: './go-nogo.component.html', + styleUrls: ['./go-nogo.component.scss'] +}) +export class GoNogoComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 2; + maxResponseTime: number = 800; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 10; + actualTrials: number = 30; + + step: number = 1; + color: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + actualAnswer: string, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (event.key === ' ') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'responded'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + + generateStimulus() { + const random = Math.random(); + if (random < 0.5) { + this.color = 'green'; + this.data.push({ + actualAnswer: 'responded', + userAnswer: 'not-responded', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + } else { + this.color = 'orange'; + this.data.push({ + actualAnswer: 'not-responded', + userAnswer: 'not-responded', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + } + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === 'responded') { + this.feedback = "Incorrect"; + } else { + this.feedback = "Too slow"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/n-back/n-back.component.html b/src/app/pages/experiments/n-back/n-back.component.html new file mode 100644 index 00000000..7baf1141 --- /dev/null +++ b/src/app/pages/experiments/n-back/n-back.component.html @@ -0,0 +1,354 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to N-back Task

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, you will be presented with letters, one at a time (not scrolling). +
+ +
+ You have to decide for each letter if it is the same as the one that was presented 2 trials ago. +
+ +
+ You have to press: +
+ LEFT ARROW, if the letter presented is not same as the one that was presented 2 trials ago +
+ RIGHT ARROW, if the letter presented is same as the one that was presented 2 trials ago +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Good luck ! You will have very little time to respond, so be ready. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ {{currentLetter}} +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ {{currentLetter}} +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/n-back/n-back.component.scss b/src/app/pages/experiments/n-back/n-back.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/n-back/n-back.component.ts b/src/app/pages/experiments/n-back/n-back.component.ts new file mode 100644 index 00000000..1e266a77 --- /dev/null +++ b/src/app/pages/experiments/n-back/n-back.component.ts @@ -0,0 +1,353 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; +import * as Set1 from './stimuli_1_1'; +import * as Set2 from './stimuli_2_1'; +import * as Set3 from './stimuli_3_1'; +import * as Set4 from './stimuli_4_1'; +import * as SetPractice from './stimuli_practice'; + +@Component({ + selector: 'app-n-back', + templateUrl: './n-back.component.html', + styleUrls: ['./n-back.component.scss'] +}) +export class NBackComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = false; + showScoreAfterEveryTrial: boolean | number = false; + numberOfBreaks: number = 0; + maxResponseTime: number = 2000; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 20; + actualTrials: number = 125; + + step: number = 1; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + actualAnswer: string, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number, + set: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + set: number; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + currentLetter: string; + nback: string; + + @HostListener('window:keydown', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (!!event.key) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + switch (event.key) { + case 'ArrowLeft': this.data[this.data.length - 1].userAnswer = 'NO'; break; + case 'ArrowRight': this.data[this.data.length - 1].userAnswer = 'YES'; break; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored; + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial; + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial; + this.numberOfBreaks = currentExperiment.numberOfBreaks; + this.maxResponseTime = currentExperiment.maxResponseTime; + this.durationOfFeedback = currentExperiment.durationOfFeedback; + this.interTrialDelay = currentExperiment.interTrialDelay; + this.practiceTrials = currentExperiment.practiceTrials; + this.actualTrials = currentExperiment.actualTrials; + this.set = Math.floor(Math.random() * 4) + 1; + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + + } + + + + generateStimulus() { + let set = this.isPractice ? 0 : this.set; + switch (set) { + case 1: + this.currentLetter = Set1.set[this.currentTrial - 1].currentLetter; + this.nback = Set1.set[this.currentTrial - 1].nback; + break; + case 2: + this.currentLetter = Set2.set[this.currentTrial - 1].currentLetter; + this.nback = Set2.set[this.currentTrial - 1].nback; + break; + case 3: + this.currentLetter = Set3.set[this.currentTrial - 1].currentLetter; + this.nback = Set3.set[this.currentTrial - 1].nback; + break; + case 4: + this.currentLetter = Set4.set[this.currentTrial - 1].currentLetter; + this.nback = Set4.set[this.currentTrial - 1].nback; + break; + default: + this.currentLetter = SetPractice.set[this.currentTrial - 1].currentLetter; + this.nback = SetPractice.set[this.currentTrial - 1].nback; + break; + } + + this.data.push({ + actualAnswer: this.currentLetter === this.nback ? 'YES' : 'NO', + userAnswer: 'NA', + responseTime: 0, + isCorrect: 0, + score: 0, + set: this.set + }); + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === 'NA') { + this.feedback = "Too slow" + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.currentLetter = ''; + this.nback = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/n-back/stimuli_1_1.ts b/src/app/pages/experiments/n-back/stimuli_1_1.ts new file mode 100644 index 00000000..be999346 --- /dev/null +++ b/src/app/pages/experiments/n-back/stimuli_1_1.ts @@ -0,0 +1,627 @@ +export const set = [ + { + "trial": 1, + "currentLetter": "W", + "nback": null + }, + { + "trial": 2, + "currentLetter": "M", + "nback": null + }, + { + "trial": 3, + "currentLetter": "F", + "nback": "W" + }, + { + "trial": 4, + "currentLetter": "V", + "nback": "M" + }, + { + "trial": 5, + "currentLetter": "O", + "nback": "F" + }, + { + "trial": 6, + "currentLetter": "W", + "nback": "V" + }, + { + "trial": 7, + "currentLetter": "V", + "nback": "O" + }, + { + "trial": 8, + "currentLetter": "G", + "nback": "W" + }, + { + "trial": 9, + "currentLetter": "D", + "nback": "V" + }, + { + "trial": 10, + "currentLetter": "H", + "nback": "G" + }, + { + "trial": 11, + "currentLetter": "F", + "nback": "D" + }, + { + "trial": 12, + "currentLetter": "D", + "nback": "H" + }, + { + "trial": 13, + "currentLetter": "A", + "nback": "F" + }, + { + "trial": 14, + "currentLetter": "L", + "nback": "D" + }, + { + "trial": 15, + "currentLetter": "W", + "nback": "A" + }, + { + "trial": 16, + "currentLetter": "U", + "nback": "L" + }, + { + "trial": 17, + "currentLetter": "Q", + "nback": "W" + }, + { + "trial": 18, + "currentLetter": "R", + "nback": "U" + }, + { + "trial": 19, + "currentLetter": "W", + "nback": "Q" + }, + { + "trial": 20, + "currentLetter": "C", + "nback": "R" + }, + { + "trial": 21, + "currentLetter": "H", + "nback": "W" + }, + { + "trial": 22, + "currentLetter": "B", + "nback": "C" + }, + { + "trial": 23, + "currentLetter": "P", + "nback": "H" + }, + { + "trial": 24, + "currentLetter": "F", + "nback": "B" + }, + { + "trial": 25, + "currentLetter": "D", + "nback": "P" + }, + { + "trial": 26, + "currentLetter": "P", + "nback": "F" + }, + { + "trial": 27, + "currentLetter": "B", + "nback": "D" + }, + { + "trial": 28, + "currentLetter": "U", + "nback": "P" + }, + { + "trial": 29, + "currentLetter": "T", + "nback": "B" + }, + { + "trial": 30, + "currentLetter": "W", + "nback": "U" + }, + { + "trial": 31, + "currentLetter": "F", + "nback": "T" + }, + { + "trial": 32, + "currentLetter": "M", + "nback": "W" + }, + { + "trial": 33, + "currentLetter": "X", + "nback": "F" + }, + { + "trial": 34, + "currentLetter": "V", + "nback": "M" + }, + { + "trial": 35, + "currentLetter": "E", + "nback": "X" + }, + { + "trial": 36, + "currentLetter": "X", + "nback": "V" + }, + { + "trial": 37, + "currentLetter": "I", + "nback": "E" + }, + { + "trial": 38, + "currentLetter": "Z", + "nback": "X" + }, + { + "trial": 39, + "currentLetter": "X", + "nback": "I" + }, + { + "trial": 40, + "currentLetter": "N", + "nback": "Z" + }, + { + "trial": 41, + "currentLetter": "R", + "nback": "X" + }, + { + "trial": 42, + "currentLetter": "O", + "nback": "N" + }, + { + "trial": 43, + "currentLetter": "E", + "nback": "R" + }, + { + "trial": 44, + "currentLetter": "Z", + "nback": "O" + }, + { + "trial": 45, + "currentLetter": "N", + "nback": "E" + }, + { + "trial": 46, + "currentLetter": "S", + "nback": "Z" + }, + { + "trial": 47, + "currentLetter": "I", + "nback": "N" + }, + { + "trial": 48, + "currentLetter": "V", + "nback": "S" + }, + { + "trial": 49, + "currentLetter": "J", + "nback": "I" + }, + { + "trial": 50, + "currentLetter": "Y", + "nback": "V" + }, + { + "trial": 51, + "currentLetter": "G", + "nback": "J" + }, + { + "trial": 52, + "currentLetter": "W", + "nback": "Y" + }, + { + "trial": 53, + "currentLetter": "A", + "nback": "G" + }, + { + "trial": 54, + "currentLetter": "D", + "nback": "W" + }, + { + "trial": 55, + "currentLetter": "W", + "nback": "A" + }, + { + "trial": 56, + "currentLetter": "S", + "nback": "D" + }, + { + "trial": 57, + "currentLetter": "D", + "nback": "W" + }, + { + "trial": 58, + "currentLetter": "I", + "nback": "S" + }, + { + "trial": 59, + "currentLetter": "E", + "nback": "D" + }, + { + "trial": 60, + "currentLetter": "S", + "nback": "I" + }, + { + "trial": 61, + "currentLetter": "D", + "nback": "E" + }, + { + "trial": 62, + "currentLetter": "R", + "nback": "S" + }, + { + "trial": 63, + "currentLetter": "H", + "nback": "D" + }, + { + "trial": 64, + "currentLetter": "S", + "nback": "R" + }, + { + "trial": 65, + "currentLetter": "F", + "nback": "H" + }, + { + "trial": 66, + "currentLetter": "Q", + "nback": "S" + }, + { + "trial": 67, + "currentLetter": "L", + "nback": "F" + }, + { + "trial": 68, + "currentLetter": "X", + "nback": "Q" + }, + { + "trial": 69, + "currentLetter": "G", + "nback": "L" + }, + { + "trial": 70, + "currentLetter": "G", + "nback": "X" + }, + { + "trial": 71, + "currentLetter": "A", + "nback": "G" + }, + { + "trial": 72, + "currentLetter": "D", + "nback": "G" + }, + { + "trial": 73, + "currentLetter": "A", + "nback": "A" + }, + { + "trial": 74, + "currentLetter": "Y", + "nback": "D" + }, + { + "trial": 75, + "currentLetter": "S", + "nback": "A" + }, + { + "trial": 76, + "currentLetter": "D", + "nback": "Y" + }, + { + "trial": 77, + "currentLetter": "I", + "nback": "S" + }, + { + "trial": 78, + "currentLetter": "C", + "nback": "D" + }, + { + "trial": 79, + "currentLetter": "N", + "nback": "I" + }, + { + "trial": 80, + "currentLetter": "Y", + "nback": "C" + }, + { + "trial": 81, + "currentLetter": "U", + "nback": "N" + }, + { + "trial": 82, + "currentLetter": "A", + "nback": "Y" + }, + { + "trial": 83, + "currentLetter": "P", + "nback": "U" + }, + { + "trial": 84, + "currentLetter": "Y", + "nback": "A" + }, + { + "trial": 85, + "currentLetter": "P", + "nback": "P" + }, + { + "trial": 86, + "currentLetter": "Y", + "nback": "Y" + }, + { + "trial": 87, + "currentLetter": "V", + "nback": "P" + }, + { + "trial": 88, + "currentLetter": "Z", + "nback": "Y" + }, + { + "trial": 89, + "currentLetter": "M", + "nback": "V" + }, + { + "trial": 90, + "currentLetter": "F", + "nback": "Z" + }, + { + "trial": 91, + "currentLetter": "C", + "nback": "M" + }, + { + "trial": 92, + "currentLetter": "O", + "nback": "F" + }, + { + "trial": 93, + "currentLetter": "G", + "nback": "C" + }, + { + "trial": 94, + "currentLetter": "S", + "nback": "O" + }, + { + "trial": 95, + "currentLetter": "M", + "nback": "G" + }, + { + "trial": 96, + "currentLetter": "D", + "nback": "S" + }, + { + "trial": 97, + "currentLetter": "I", + "nback": "M" + }, + { + "trial": 98, + "currentLetter": "R", + "nback": "D" + }, + { + "trial": 99, + "currentLetter": "H", + "nback": "I" + }, + { + "trial": 100, + "currentLetter": "N", + "nback": "R" + }, + { + "trial": 101, + "currentLetter": "A", + "nback": "H" + }, + { + "trial": 102, + "currentLetter": "L", + "nback": "N" + }, + { + "trial": 103, + "currentLetter": "O", + "nback": "A" + }, + { + "trial": 104, + "currentLetter": "I", + "nback": "L" + }, + { + "trial": 105, + "currentLetter": "P", + "nback": "O" + }, + { + "trial": 106, + "currentLetter": "Q", + "nback": "I" + }, + { + "trial": 107, + "currentLetter": "F", + "nback": "P" + }, + { + "trial": 108, + "currentLetter": "N", + "nback": "Q" + }, + { + "trial": 109, + "currentLetter": "Y", + "nback": "F" + }, + { + "trial": 110, + "currentLetter": "H", + "nback": "N" + }, + { + "trial": 111, + "currentLetter": "C", + "nback": "Y" + }, + { + "trial": 112, + "currentLetter": "W", + "nback": "H" + }, + { + "trial": 113, + "currentLetter": "A", + "nback": "C" + }, + { + "trial": 114, + "currentLetter": "A", + "nback": "W" + }, + { + "trial": 115, + "currentLetter": "N", + "nback": "A" + }, + { + "trial": 116, + "currentLetter": "Z", + "nback": "A" + }, + { + "trial": 117, + "currentLetter": "E", + "nback": "N" + }, + { + "trial": 118, + "currentLetter": "Z", + "nback": "Z" + }, + { + "trial": 119, + "currentLetter": "R", + "nback": "E" + }, + { + "trial": 120, + "currentLetter": "C", + "nback": "Z" + }, + { + "trial": 121, + "currentLetter": "K", + "nback": "R" + }, + { + "trial": 122, + "currentLetter": "B", + "nback": "C" + }, + { + "trial": 123, + "currentLetter": "W", + "nback": "K" + }, + { + "trial": 124, + "currentLetter": "G", + "nback": "B" + }, + { + "trial": 125, + "currentLetter": "U", + "nback": "W" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/n-back/stimuli_2_1.ts b/src/app/pages/experiments/n-back/stimuli_2_1.ts new file mode 100644 index 00000000..a36c5d58 --- /dev/null +++ b/src/app/pages/experiments/n-back/stimuli_2_1.ts @@ -0,0 +1,627 @@ +export const set = [ + { + "trial": 1, + "currentLetter": "F", + "nback": null + }, + { + "trial": 2, + "currentLetter": "Q", + "nback": null + }, + { + "trial": 3, + "currentLetter": "X", + "nback": "F" + }, + { + "trial": 4, + "currentLetter": "F", + "nback": "Q" + }, + { + "trial": 5, + "currentLetter": "K", + "nback": "X" + }, + { + "trial": 6, + "currentLetter": "H", + "nback": "F" + }, + { + "trial": 7, + "currentLetter": "T", + "nback": "K" + }, + { + "trial": 8, + "currentLetter": "K", + "nback": "H" + }, + { + "trial": 9, + "currentLetter": "E", + "nback": "T" + }, + { + "trial": 10, + "currentLetter": "G", + "nback": "K" + }, + { + "trial": 11, + "currentLetter": "B", + "nback": "E" + }, + { + "trial": 12, + "currentLetter": "C", + "nback": "G" + }, + { + "trial": 13, + "currentLetter": "A", + "nback": "B" + }, + { + "trial": 14, + "currentLetter": "Q", + "nback": "C" + }, + { + "trial": 15, + "currentLetter": "X", + "nback": "A" + }, + { + "trial": 16, + "currentLetter": "W", + "nback": "Q" + }, + { + "trial": 17, + "currentLetter": "N", + "nback": "X" + }, + { + "trial": 18, + "currentLetter": "P", + "nback": "W" + }, + { + "trial": 19, + "currentLetter": "M", + "nback": "N" + }, + { + "trial": 20, + "currentLetter": "F", + "nback": "P" + }, + { + "trial": 21, + "currentLetter": "F", + "nback": "M" + }, + { + "trial": 22, + "currentLetter": "G", + "nback": "F" + }, + { + "trial": 23, + "currentLetter": "Q", + "nback": "F" + }, + { + "trial": 24, + "currentLetter": "T", + "nback": "G" + }, + { + "trial": 25, + "currentLetter": "L", + "nback": "Q" + }, + { + "trial": 26, + "currentLetter": "R", + "nback": "T" + }, + { + "trial": 27, + "currentLetter": "L", + "nback": "L" + }, + { + "trial": 28, + "currentLetter": "S", + "nback": "R" + }, + { + "trial": 29, + "currentLetter": "P", + "nback": "L" + }, + { + "trial": 30, + "currentLetter": "D", + "nback": "S" + }, + { + "trial": 31, + "currentLetter": "I", + "nback": "P" + }, + { + "trial": 32, + "currentLetter": "W", + "nback": "D" + }, + { + "trial": 33, + "currentLetter": "O", + "nback": "I" + }, + { + "trial": 34, + "currentLetter": "A", + "nback": "W" + }, + { + "trial": 35, + "currentLetter": "T", + "nback": "O" + }, + { + "trial": 36, + "currentLetter": "S", + "nback": "A" + }, + { + "trial": 37, + "currentLetter": "G", + "nback": "T" + }, + { + "trial": 38, + "currentLetter": "E", + "nback": "S" + }, + { + "trial": 39, + "currentLetter": "A", + "nback": "G" + }, + { + "trial": 40, + "currentLetter": "G", + "nback": "E" + }, + { + "trial": 41, + "currentLetter": "O", + "nback": "A" + }, + { + "trial": 42, + "currentLetter": "L", + "nback": "G" + }, + { + "trial": 43, + "currentLetter": "W", + "nback": "O" + }, + { + "trial": 44, + "currentLetter": "X", + "nback": "L" + }, + { + "trial": 45, + "currentLetter": "V", + "nback": "W" + }, + { + "trial": 46, + "currentLetter": "L", + "nback": "X" + }, + { + "trial": 47, + "currentLetter": "D", + "nback": "V" + }, + { + "trial": 48, + "currentLetter": "K", + "nback": "L" + }, + { + "trial": 49, + "currentLetter": "C", + "nback": "D" + }, + { + "trial": 50, + "currentLetter": "A", + "nback": "K" + }, + { + "trial": 51, + "currentLetter": "W", + "nback": "C" + }, + { + "trial": 52, + "currentLetter": "A", + "nback": "A" + }, + { + "trial": 53, + "currentLetter": "R", + "nback": "W" + }, + { + "trial": 54, + "currentLetter": "H", + "nback": "A" + }, + { + "trial": 55, + "currentLetter": "S", + "nback": "R" + }, + { + "trial": 56, + "currentLetter": "E", + "nback": "H" + }, + { + "trial": 57, + "currentLetter": "A", + "nback": "S" + }, + { + "trial": 58, + "currentLetter": "K", + "nback": "E" + }, + { + "trial": 59, + "currentLetter": "V", + "nback": "A" + }, + { + "trial": 60, + "currentLetter": "Y", + "nback": "K" + }, + { + "trial": 61, + "currentLetter": "C", + "nback": "V" + }, + { + "trial": 62, + "currentLetter": "F", + "nback": "Y" + }, + { + "trial": 63, + "currentLetter": "C", + "nback": "C" + }, + { + "trial": 64, + "currentLetter": "L", + "nback": "F" + }, + { + "trial": 65, + "currentLetter": "K", + "nback": "C" + }, + { + "trial": 66, + "currentLetter": "Q", + "nback": "L" + }, + { + "trial": 67, + "currentLetter": "Q", + "nback": "K" + }, + { + "trial": 68, + "currentLetter": "X", + "nback": "Q" + }, + { + "trial": 69, + "currentLetter": "O", + "nback": "Q" + }, + { + "trial": 70, + "currentLetter": "F", + "nback": "X" + }, + { + "trial": 71, + "currentLetter": "Z", + "nback": "O" + }, + { + "trial": 72, + "currentLetter": "L", + "nback": "F" + }, + { + "trial": 73, + "currentLetter": "S", + "nback": "Z" + }, + { + "trial": 74, + "currentLetter": "P", + "nback": "L" + }, + { + "trial": 75, + "currentLetter": "F", + "nback": "S" + }, + { + "trial": 76, + "currentLetter": "P", + "nback": "P" + }, + { + "trial": 77, + "currentLetter": "X", + "nback": "F" + }, + { + "trial": 78, + "currentLetter": "J", + "nback": "P" + }, + { + "trial": 79, + "currentLetter": "T", + "nback": "X" + }, + { + "trial": 80, + "currentLetter": "V", + "nback": "J" + }, + { + "trial": 81, + "currentLetter": "Q", + "nback": "T" + }, + { + "trial": 82, + "currentLetter": "W", + "nback": "V" + }, + { + "trial": 83, + "currentLetter": "O", + "nback": "Q" + }, + { + "trial": 84, + "currentLetter": "X", + "nback": "W" + }, + { + "trial": 85, + "currentLetter": "R", + "nback": "O" + }, + { + "trial": 86, + "currentLetter": "K", + "nback": "X" + }, + { + "trial": 87, + "currentLetter": "Z", + "nback": "R" + }, + { + "trial": 88, + "currentLetter": "N", + "nback": "K" + }, + { + "trial": 89, + "currentLetter": "N", + "nback": "Z" + }, + { + "trial": 90, + "currentLetter": "S", + "nback": "N" + }, + { + "trial": 91, + "currentLetter": "T", + "nback": "N" + }, + { + "trial": 92, + "currentLetter": "X", + "nback": "S" + }, + { + "trial": 93, + "currentLetter": "A", + "nback": "T" + }, + { + "trial": 94, + "currentLetter": "W", + "nback": "X" + }, + { + "trial": 95, + "currentLetter": "V", + "nback": "A" + }, + { + "trial": 96, + "currentLetter": "M", + "nback": "W" + }, + { + "trial": 97, + "currentLetter": "N", + "nback": "V" + }, + { + "trial": 98, + "currentLetter": "L", + "nback": "M" + }, + { + "trial": 99, + "currentLetter": "N", + "nback": "N" + }, + { + "trial": 100, + "currentLetter": "F", + "nback": "L" + }, + { + "trial": 101, + "currentLetter": "U", + "nback": "N" + }, + { + "trial": 102, + "currentLetter": "H", + "nback": "F" + }, + { + "trial": 103, + "currentLetter": "P", + "nback": "U" + }, + { + "trial": 104, + "currentLetter": "S", + "nback": "H" + }, + { + "trial": 105, + "currentLetter": "X", + "nback": "P" + }, + { + "trial": 106, + "currentLetter": "Q", + "nback": "S" + }, + { + "trial": 107, + "currentLetter": "I", + "nback": "X" + }, + { + "trial": 108, + "currentLetter": "Q", + "nback": "Q" + }, + { + "trial": 109, + "currentLetter": "U", + "nback": "I" + }, + { + "trial": 110, + "currentLetter": "N", + "nback": "Q" + }, + { + "trial": 111, + "currentLetter": "H", + "nback": "U" + }, + { + "trial": 112, + "currentLetter": "B", + "nback": "N" + }, + { + "trial": 113, + "currentLetter": "W", + "nback": "H" + }, + { + "trial": 114, + "currentLetter": "I", + "nback": "B" + }, + { + "trial": 115, + "currentLetter": "W", + "nback": "W" + }, + { + "trial": 116, + "currentLetter": "I", + "nback": "I" + }, + { + "trial": 117, + "currentLetter": "W", + "nback": "W" + }, + { + "trial": 118, + "currentLetter": "Y", + "nback": "I" + }, + { + "trial": 119, + "currentLetter": "U", + "nback": "W" + }, + { + "trial": 120, + "currentLetter": "C", + "nback": "Y" + }, + { + "trial": 121, + "currentLetter": "J", + "nback": "U" + }, + { + "trial": 122, + "currentLetter": "Y", + "nback": "C" + }, + { + "trial": 123, + "currentLetter": "Z", + "nback": "J" + }, + { + "trial": 124, + "currentLetter": "X", + "nback": "Y" + }, + { + "trial": 125, + "currentLetter": "O", + "nback": "Z" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/n-back/stimuli_3_1.ts b/src/app/pages/experiments/n-back/stimuli_3_1.ts new file mode 100644 index 00000000..ecd2c34b --- /dev/null +++ b/src/app/pages/experiments/n-back/stimuli_3_1.ts @@ -0,0 +1,627 @@ +export const set = [ + { + "trial": 1, + "currentLetter": "C", + "nback": null + }, + { + "trial": 2, + "currentLetter": "I", + "nback": null + }, + { + "trial": 3, + "currentLetter": "G", + "nback": "C" + }, + { + "trial": 4, + "currentLetter": "K", + "nback": "I" + }, + { + "trial": 5, + "currentLetter": "R", + "nback": "G" + }, + { + "trial": 6, + "currentLetter": "G", + "nback": "K" + }, + { + "trial": 7, + "currentLetter": "C", + "nback": "R" + }, + { + "trial": 8, + "currentLetter": "A", + "nback": "G" + }, + { + "trial": 9, + "currentLetter": "M", + "nback": "C" + }, + { + "trial": 10, + "currentLetter": "Q", + "nback": "A" + }, + { + "trial": 11, + "currentLetter": "N", + "nback": "M" + }, + { + "trial": 12, + "currentLetter": "E", + "nback": "Q" + }, + { + "trial": 13, + "currentLetter": "X", + "nback": "N" + }, + { + "trial": 14, + "currentLetter": "F", + "nback": "E" + }, + { + "trial": 15, + "currentLetter": "I", + "nback": "X" + }, + { + "trial": 16, + "currentLetter": "C", + "nback": "F" + }, + { + "trial": 17, + "currentLetter": "W", + "nback": "I" + }, + { + "trial": 18, + "currentLetter": "O", + "nback": "C" + }, + { + "trial": 19, + "currentLetter": "V", + "nback": "W" + }, + { + "trial": 20, + "currentLetter": "R", + "nback": "O" + }, + { + "trial": 21, + "currentLetter": "M", + "nback": "V" + }, + { + "trial": 22, + "currentLetter": "C", + "nback": "R" + }, + { + "trial": 23, + "currentLetter": "A", + "nback": "M" + }, + { + "trial": 24, + "currentLetter": "F", + "nback": "C" + }, + { + "trial": 25, + "currentLetter": "J", + "nback": "A" + }, + { + "trial": 26, + "currentLetter": "S", + "nback": "F" + }, + { + "trial": 27, + "currentLetter": "C", + "nback": "J" + }, + { + "trial": 28, + "currentLetter": "X", + "nback": "S" + }, + { + "trial": 29, + "currentLetter": "Y", + "nback": "C" + }, + { + "trial": 30, + "currentLetter": "H", + "nback": "X" + }, + { + "trial": 31, + "currentLetter": "X", + "nback": "Y" + }, + { + "trial": 32, + "currentLetter": "M", + "nback": "H" + }, + { + "trial": 33, + "currentLetter": "V", + "nback": "X" + }, + { + "trial": 34, + "currentLetter": "V", + "nback": "M" + }, + { + "trial": 35, + "currentLetter": "G", + "nback": "V" + }, + { + "trial": 36, + "currentLetter": "W", + "nback": "V" + }, + { + "trial": 37, + "currentLetter": "S", + "nback": "G" + }, + { + "trial": 38, + "currentLetter": "F", + "nback": "W" + }, + { + "trial": 39, + "currentLetter": "O", + "nback": "S" + }, + { + "trial": 40, + "currentLetter": "Q", + "nback": "F" + }, + { + "trial": 41, + "currentLetter": "L", + "nback": "O" + }, + { + "trial": 42, + "currentLetter": "L", + "nback": "Q" + }, + { + "trial": 43, + "currentLetter": "V", + "nback": "L" + }, + { + "trial": 44, + "currentLetter": "Z", + "nback": "L" + }, + { + "trial": 45, + "currentLetter": "C", + "nback": "V" + }, + { + "trial": 46, + "currentLetter": "J", + "nback": "Z" + }, + { + "trial": 47, + "currentLetter": "I", + "nback": "C" + }, + { + "trial": 48, + "currentLetter": "X", + "nback": "J" + }, + { + "trial": 49, + "currentLetter": "Y", + "nback": "I" + }, + { + "trial": 50, + "currentLetter": "U", + "nback": "X" + }, + { + "trial": 51, + "currentLetter": "P", + "nback": "Y" + }, + { + "trial": 52, + "currentLetter": "P", + "nback": "U" + }, + { + "trial": 53, + "currentLetter": "I", + "nback": "P" + }, + { + "trial": 54, + "currentLetter": "Y", + "nback": "P" + }, + { + "trial": 55, + "currentLetter": "R", + "nback": "I" + }, + { + "trial": 56, + "currentLetter": "F", + "nback": "Y" + }, + { + "trial": 57, + "currentLetter": "Z", + "nback": "R" + }, + { + "trial": 58, + "currentLetter": "W", + "nback": "F" + }, + { + "trial": 59, + "currentLetter": "F", + "nback": "Z" + }, + { + "trial": 60, + "currentLetter": "C", + "nback": "W" + }, + { + "trial": 61, + "currentLetter": "P", + "nback": "F" + }, + { + "trial": 62, + "currentLetter": "S", + "nback": "C" + }, + { + "trial": 63, + "currentLetter": "P", + "nback": "P" + }, + { + "trial": 64, + "currentLetter": "S", + "nback": "S" + }, + { + "trial": 65, + "currentLetter": "M", + "nback": "P" + }, + { + "trial": 66, + "currentLetter": "S", + "nback": "S" + }, + { + "trial": 67, + "currentLetter": "S", + "nback": "M" + }, + { + "trial": 68, + "currentLetter": "M", + "nback": "S" + }, + { + "trial": 69, + "currentLetter": "Y", + "nback": "S" + }, + { + "trial": 70, + "currentLetter": "K", + "nback": "M" + }, + { + "trial": 71, + "currentLetter": "Q", + "nback": "Y" + }, + { + "trial": 72, + "currentLetter": "E", + "nback": "K" + }, + { + "trial": 73, + "currentLetter": "C", + "nback": "Q" + }, + { + "trial": 74, + "currentLetter": "J", + "nback": "E" + }, + { + "trial": 75, + "currentLetter": "K", + "nback": "C" + }, + { + "trial": 76, + "currentLetter": "T", + "nback": "J" + }, + { + "trial": 77, + "currentLetter": "N", + "nback": "K" + }, + { + "trial": 78, + "currentLetter": "E", + "nback": "T" + }, + { + "trial": 79, + "currentLetter": "U", + "nback": "N" + }, + { + "trial": 80, + "currentLetter": "T", + "nback": "E" + }, + { + "trial": 81, + "currentLetter": "P", + "nback": "U" + }, + { + "trial": 82, + "currentLetter": "K", + "nback": "T" + }, + { + "trial": 83, + "currentLetter": "Z", + "nback": "P" + }, + { + "trial": 84, + "currentLetter": "O", + "nback": "K" + }, + { + "trial": 85, + "currentLetter": "T", + "nback": "Z" + }, + { + "trial": 86, + "currentLetter": "B", + "nback": "O" + }, + { + "trial": 87, + "currentLetter": "W", + "nback": "T" + }, + { + "trial": 88, + "currentLetter": "T", + "nback": "B" + }, + { + "trial": 89, + "currentLetter": "J", + "nback": "W" + }, + { + "trial": 90, + "currentLetter": "X", + "nback": "T" + }, + { + "trial": 91, + "currentLetter": "D", + "nback": "J" + }, + { + "trial": 92, + "currentLetter": "W", + "nback": "X" + }, + { + "trial": 93, + "currentLetter": "T", + "nback": "D" + }, + { + "trial": 94, + "currentLetter": "H", + "nback": "W" + }, + { + "trial": 95, + "currentLetter": "Z", + "nback": "T" + }, + { + "trial": 96, + "currentLetter": "P", + "nback": "H" + }, + { + "trial": 97, + "currentLetter": "L", + "nback": "Z" + }, + { + "trial": 98, + "currentLetter": "R", + "nback": "P" + }, + { + "trial": 99, + "currentLetter": "F", + "nback": "L" + }, + { + "trial": 100, + "currentLetter": "M", + "nback": "R" + }, + { + "trial": 101, + "currentLetter": "J", + "nback": "F" + }, + { + "trial": 102, + "currentLetter": "H", + "nback": "M" + }, + { + "trial": 103, + "currentLetter": "V", + "nback": "J" + }, + { + "trial": 104, + "currentLetter": "L", + "nback": "H" + }, + { + "trial": 105, + "currentLetter": "C", + "nback": "V" + }, + { + "trial": 106, + "currentLetter": "M", + "nback": "L" + }, + { + "trial": 107, + "currentLetter": "P", + "nback": "C" + }, + { + "trial": 108, + "currentLetter": "Z", + "nback": "M" + }, + { + "trial": 109, + "currentLetter": "B", + "nback": "P" + }, + { + "trial": 110, + "currentLetter": "N", + "nback": "Z" + }, + { + "trial": 111, + "currentLetter": "R", + "nback": "B" + }, + { + "trial": 112, + "currentLetter": "A", + "nback": "N" + }, + { + "trial": 113, + "currentLetter": "O", + "nback": "R" + }, + { + "trial": 114, + "currentLetter": "K", + "nback": "A" + }, + { + "trial": 115, + "currentLetter": "J", + "nback": "O" + }, + { + "trial": 116, + "currentLetter": "E", + "nback": "K" + }, + { + "trial": 117, + "currentLetter": "W", + "nback": "J" + }, + { + "trial": 118, + "currentLetter": "Z", + "nback": "E" + }, + { + "trial": 119, + "currentLetter": "H", + "nback": "W" + }, + { + "trial": 120, + "currentLetter": "K", + "nback": "Z" + }, + { + "trial": 121, + "currentLetter": "Q", + "nback": "H" + }, + { + "trial": 122, + "currentLetter": "Y", + "nback": "K" + }, + { + "trial": 123, + "currentLetter": "Q", + "nback": "Q" + }, + { + "trial": 124, + "currentLetter": "G", + "nback": "Y" + }, + { + "trial": 125, + "currentLetter": "H", + "nback": "Q" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/n-back/stimuli_4_1.ts b/src/app/pages/experiments/n-back/stimuli_4_1.ts new file mode 100644 index 00000000..0d81eccb --- /dev/null +++ b/src/app/pages/experiments/n-back/stimuli_4_1.ts @@ -0,0 +1,627 @@ +export const set = [ + { + "trial": 1, + "currentLetter": "G", + "nback": null + }, + { + "trial": 2, + "currentLetter": "A", + "nback": null + }, + { + "trial": 3, + "currentLetter": "O", + "nback": "G" + }, + { + "trial": 4, + "currentLetter": "Z", + "nback": "A" + }, + { + "trial": 5, + "currentLetter": "I", + "nback": "O" + }, + { + "trial": 6, + "currentLetter": "W", + "nback": "Z" + }, + { + "trial": 7, + "currentLetter": "B", + "nback": "I" + }, + { + "trial": 8, + "currentLetter": "B", + "nback": "W" + }, + { + "trial": 9, + "currentLetter": "E", + "nback": "B" + }, + { + "trial": 10, + "currentLetter": "L", + "nback": "B" + }, + { + "trial": 11, + "currentLetter": "Y", + "nback": "E" + }, + { + "trial": 12, + "currentLetter": "I", + "nback": "L" + }, + { + "trial": 13, + "currentLetter": "K", + "nback": "Y" + }, + { + "trial": 14, + "currentLetter": "Q", + "nback": "I" + }, + { + "trial": 15, + "currentLetter": "B", + "nback": "K" + }, + { + "trial": 16, + "currentLetter": "A", + "nback": "Q" + }, + { + "trial": 17, + "currentLetter": "C", + "nback": "B" + }, + { + "trial": 18, + "currentLetter": "H", + "nback": "A" + }, + { + "trial": 19, + "currentLetter": "L", + "nback": "C" + }, + { + "trial": 20, + "currentLetter": "G", + "nback": "H" + }, + { + "trial": 21, + "currentLetter": "B", + "nback": "L" + }, + { + "trial": 22, + "currentLetter": "L", + "nback": "G" + }, + { + "trial": 23, + "currentLetter": "F", + "nback": "B" + }, + { + "trial": 24, + "currentLetter": "G", + "nback": "L" + }, + { + "trial": 25, + "currentLetter": "W", + "nback": "F" + }, + { + "trial": 26, + "currentLetter": "L", + "nback": "G" + }, + { + "trial": 27, + "currentLetter": "D", + "nback": "W" + }, + { + "trial": 28, + "currentLetter": "U", + "nback": "L" + }, + { + "trial": 29, + "currentLetter": "L", + "nback": "D" + }, + { + "trial": 30, + "currentLetter": "X", + "nback": "U" + }, + { + "trial": 31, + "currentLetter": "R", + "nback": "L" + }, + { + "trial": 32, + "currentLetter": "O", + "nback": "X" + }, + { + "trial": 33, + "currentLetter": "L", + "nback": "R" + }, + { + "trial": 34, + "currentLetter": "X", + "nback": "O" + }, + { + "trial": 35, + "currentLetter": "D", + "nback": "L" + }, + { + "trial": 36, + "currentLetter": "M", + "nback": "X" + }, + { + "trial": 37, + "currentLetter": "L", + "nback": "D" + }, + { + "trial": 38, + "currentLetter": "W", + "nback": "M" + }, + { + "trial": 39, + "currentLetter": "K", + "nback": "L" + }, + { + "trial": 40, + "currentLetter": "F", + "nback": "W" + }, + { + "trial": 41, + "currentLetter": "K", + "nback": "K" + }, + { + "trial": 42, + "currentLetter": "P", + "nback": "F" + }, + { + "trial": 43, + "currentLetter": "R", + "nback": "K" + }, + { + "trial": 44, + "currentLetter": "M", + "nback": "P" + }, + { + "trial": 45, + "currentLetter": "T", + "nback": "R" + }, + { + "trial": 46, + "currentLetter": "Z", + "nback": "M" + }, + { + "trial": 47, + "currentLetter": "A", + "nback": "T" + }, + { + "trial": 48, + "currentLetter": "Y", + "nback": "Z" + }, + { + "trial": 49, + "currentLetter": "L", + "nback": "A" + }, + { + "trial": 50, + "currentLetter": "T", + "nback": "Y" + }, + { + "trial": 51, + "currentLetter": "O", + "nback": "L" + }, + { + "trial": 52, + "currentLetter": "P", + "nback": "T" + }, + { + "trial": 53, + "currentLetter": "V", + "nback": "O" + }, + { + "trial": 54, + "currentLetter": "Y", + "nback": "P" + }, + { + "trial": 55, + "currentLetter": "D", + "nback": "V" + }, + { + "trial": 56, + "currentLetter": "Z", + "nback": "Y" + }, + { + "trial": 57, + "currentLetter": "K", + "nback": "D" + }, + { + "trial": 58, + "currentLetter": "U", + "nback": "Z" + }, + { + "trial": 59, + "currentLetter": "F", + "nback": "K" + }, + { + "trial": 60, + "currentLetter": "X", + "nback": "U" + }, + { + "trial": 61, + "currentLetter": "S", + "nback": "F" + }, + { + "trial": 62, + "currentLetter": "G", + "nback": "X" + }, + { + "trial": 63, + "currentLetter": "V", + "nback": "S" + }, + { + "trial": 64, + "currentLetter": "V", + "nback": "G" + }, + { + "trial": 65, + "currentLetter": "A", + "nback": "V" + }, + { + "trial": 66, + "currentLetter": "C", + "nback": "V" + }, + { + "trial": 67, + "currentLetter": "U", + "nback": "A" + }, + { + "trial": 68, + "currentLetter": "I", + "nback": "C" + }, + { + "trial": 69, + "currentLetter": "V", + "nback": "U" + }, + { + "trial": 70, + "currentLetter": "U", + "nback": "I" + }, + { + "trial": 71, + "currentLetter": "D", + "nback": "V" + }, + { + "trial": 72, + "currentLetter": "F", + "nback": "U" + }, + { + "trial": 73, + "currentLetter": "I", + "nback": "D" + }, + { + "trial": 74, + "currentLetter": "G", + "nback": "F" + }, + { + "trial": 75, + "currentLetter": "R", + "nback": "I" + }, + { + "trial": 76, + "currentLetter": "L", + "nback": "G" + }, + { + "trial": 77, + "currentLetter": "Q", + "nback": "R" + }, + { + "trial": 78, + "currentLetter": "P", + "nback": "L" + }, + { + "trial": 79, + "currentLetter": "F", + "nback": "Q" + }, + { + "trial": 80, + "currentLetter": "B", + "nback": "P" + }, + { + "trial": 81, + "currentLetter": "S", + "nback": "F" + }, + { + "trial": 82, + "currentLetter": "B", + "nback": "B" + }, + { + "trial": 83, + "currentLetter": "Q", + "nback": "S" + }, + { + "trial": 84, + "currentLetter": "U", + "nback": "B" + }, + { + "trial": 85, + "currentLetter": "L", + "nback": "Q" + }, + { + "trial": 86, + "currentLetter": "K", + "nback": "U" + }, + { + "trial": 87, + "currentLetter": "I", + "nback": "L" + }, + { + "trial": 88, + "currentLetter": "M", + "nback": "K" + }, + { + "trial": 89, + "currentLetter": "W", + "nback": "I" + }, + { + "trial": 90, + "currentLetter": "N", + "nback": "M" + }, + { + "trial": 91, + "currentLetter": "J", + "nback": "W" + }, + { + "trial": 92, + "currentLetter": "Q", + "nback": "N" + }, + { + "trial": 93, + "currentLetter": "X", + "nback": "J" + }, + { + "trial": 94, + "currentLetter": "I", + "nback": "Q" + }, + { + "trial": 95, + "currentLetter": "E", + "nback": "X" + }, + { + "trial": 96, + "currentLetter": "X", + "nback": "I" + }, + { + "trial": 97, + "currentLetter": "Z", + "nback": "E" + }, + { + "trial": 98, + "currentLetter": "R", + "nback": "X" + }, + { + "trial": 99, + "currentLetter": "H", + "nback": "Z" + }, + { + "trial": 100, + "currentLetter": "O", + "nback": "R" + }, + { + "trial": 101, + "currentLetter": "N", + "nback": "H" + }, + { + "trial": 102, + "currentLetter": "V", + "nback": "O" + }, + { + "trial": 103, + "currentLetter": "J", + "nback": "N" + }, + { + "trial": 104, + "currentLetter": "S", + "nback": "V" + }, + { + "trial": 105, + "currentLetter": "A", + "nback": "J" + }, + { + "trial": 106, + "currentLetter": "C", + "nback": "S" + }, + { + "trial": 107, + "currentLetter": "S", + "nback": "A" + }, + { + "trial": 108, + "currentLetter": "C", + "nback": "C" + }, + { + "trial": 109, + "currentLetter": "U", + "nback": "S" + }, + { + "trial": 110, + "currentLetter": "U", + "nback": "C" + }, + { + "trial": 111, + "currentLetter": "X", + "nback": "U" + }, + { + "trial": 112, + "currentLetter": "I", + "nback": "U" + }, + { + "trial": 113, + "currentLetter": "J", + "nback": "X" + }, + { + "trial": 114, + "currentLetter": "B", + "nback": "I" + }, + { + "trial": 115, + "currentLetter": "H", + "nback": "J" + }, + { + "trial": 116, + "currentLetter": "F", + "nback": "B" + }, + { + "trial": 117, + "currentLetter": "Y", + "nback": "H" + }, + { + "trial": 118, + "currentLetter": "W", + "nback": "F" + }, + { + "trial": 119, + "currentLetter": "O", + "nback": "Y" + }, + { + "trial": 120, + "currentLetter": "X", + "nback": "W" + }, + { + "trial": 121, + "currentLetter": "I", + "nback": "O" + }, + { + "trial": 122, + "currentLetter": "H", + "nback": "X" + }, + { + "trial": 123, + "currentLetter": "Q", + "nback": "I" + }, + { + "trial": 124, + "currentLetter": "X", + "nback": "H" + }, + { + "trial": 125, + "currentLetter": "L", + "nback": "Q" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/n-back/stimuli_practice.ts b/src/app/pages/experiments/n-back/stimuli_practice.ts new file mode 100644 index 00000000..a5e6060e --- /dev/null +++ b/src/app/pages/experiments/n-back/stimuli_practice.ts @@ -0,0 +1,102 @@ +export const set = [ + { + "trial": 1, + "currentLetter": "F", + "nback": null + }, + { + "trial": 2, + "currentLetter": "R", + "nback": null + }, + { + "trial": 3, + "currentLetter": "J", + "nback": "F" + }, + { + "trial": 4, + "currentLetter": "T", + "nback": "R" + }, + { + "trial": 5, + "currentLetter": "G", + "nback": "J" + }, + { + "trial": 6, + "currentLetter": "M", + "nback": "T" + }, + { + "trial": 7, + "currentLetter": "J", + "nback": "G" + }, + { + "trial": 8, + "currentLetter": "E", + "nback": "M" + }, + { + "trial": 9, + "currentLetter": "P", + "nback": "J" + }, + { + "trial": 10, + "currentLetter": "O", + "nback": "E" + }, + { + "trial": 11, + "currentLetter": "I", + "nback": "P" + }, + { + "trial": 12, + "currentLetter": "J", + "nback": "O" + }, + { + "trial": 13, + "currentLetter": "I", + "nback": "I" + }, + { + "trial": 14, + "currentLetter": "A", + "nback": "J" + }, + { + "trial": 15, + "currentLetter": "P", + "nback": "I" + }, + { + "trial": 16, + "currentLetter": "D", + "nback": "A" + }, + { + "trial": 17, + "currentLetter": "F", + "nback": "P" + }, + { + "trial": 18, + "currentLetter": "Q", + "nback": "D" + }, + { + "trial": 19, + "currentLetter": "I", + "nback": "F" + }, + { + "trial": 20, + "currentLetter": "K", + "nback": "Q" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/shape-game/shape-game.component.html b/src/app/pages/experiments/shape-game/shape-game.component.html new file mode 100644 index 00000000..def13ab8 --- /dev/null +++ b/src/app/pages/experiments/shape-game/shape-game.component.html @@ -0,0 +1,498 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Shape Game

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ Now, you will be shown 6 shapes on the screen. +
+ +
+ ONE of these is different than the others. +
+ +
+ Your job is to tell us if the bar inside the UNIQUE shape is horizontal or vertical. You should + ignore the + colours. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+

+

+
+ +
+ For instance, here the unique shape has a horizontal bar: +
+ +
+ Press the Z key if the bar is horizontal. +
+ +
+ Press the M key if the bar is vertical. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Remember, +
+ Press the Z key if the bar is horizontal. +
+ Press the M key if the bar is vertical. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn between 1-10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, +
+ Press the Z key if the bar is horizontal. +
+ Press the M key if the bar is vertical. +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/shape-game/shape-game.component.scss b/src/app/pages/experiments/shape-game/shape-game.component.scss new file mode 100644 index 00000000..0eb31b89 --- /dev/null +++ b/src/app/pages/experiments/shape-game/shape-game.component.scss @@ -0,0 +1,37 @@ +table{ + td{ + width: 120px; + height: 120px; + text-align: center; + div{ + display: inline-block; + } + .line{ + position: fixed; + height: 12px; + width: 55px; + margin-top: 32.5px; + margin-left: 8.5px; + background-color: black; + } + .line2{ + position: fixed; + height: 12px; + width: 55px; + margin-top: 31px; + margin-left: 8px; + background-color: black; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + } + .m{ + transform: rotate(90deg); + } + .s{ + // transform: rotate(45deg); + } + .z{ + transform: rotate(0deg); + } + } +} \ No newline at end of file diff --git a/src/app/pages/experiments/shape-game/shape-game.component.ts b/src/app/pages/experiments/shape-game/shape-game.component.ts new file mode 100644 index 00000000..dca03641 --- /dev/null +++ b/src/app/pages/experiments/shape-game/shape-game.component.ts @@ -0,0 +1,448 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; +@Component({ + selector: 'app-shape-game', + templateUrl: './shape-game.component.html', + styleUrls: ['./shape-game.component.scss'] +}) +export class ShapeGameComponent implements OnInit { + + + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 0; + maxResponseTime: number = 800; + durationOfFeedback: number = 500; + interTrialDelay: number = 1000; + practiceTrials: number = 10; + actualTrials: number = 30; + step: number = 1; + color: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: any[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + colors = []; + + c = { + a: '', + b: '', + c: '', + d: '', + e: '', + f: '' + }; + + a = { + a: 's', + b: 's', + c: 's', + d: 's', + e: 's', + f: 's' + }; + + s = { + a: '', + b: '', + c: '', + d: '', + e: '', + f: '' + }; + + colors_all = [ + 'blue', + 'orange', + 'brown', + 'grey', + 'purple' + ]; + + trial_reward_probs = []; + trial_colors = []; + + + @HostListener('window:keydown', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (event.key === 'z' || event.key === 'm') { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (!!event.key) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + switch (event.key) { + case 'z': this.data[this.data.length - 1].userAnswer = 'Z'; break; + case 'm': this.data[this.data.length - 1].userAnswer = 'M'; break; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.calculateProbs(); + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.calculateProbs(); + this.showStimulus(); + } + + + calculateProbs() { + let trials_max = 30; + if (this.isPractice) { + trials_max = this.practiceTrials; + } else { + trials_max = this.actualTrials; + } + this.trial_reward_probs = []; + this.trial_colors = []; + for (let i = 0; i < trials_max; i++) { + if (i < (trials_max / 2)) { + this.trial_colors.push('red'); + this.trial_reward_probs.push(0.1); + } else { + this.trial_colors.push('teal'); + this.trial_reward_probs.push(0.9); + } + } + this.trial_colors = this.shuffle(this.trial_colors); + this.trial_reward_probs = this.shuffle(this.trial_reward_probs); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + generateStimulus() { + + this.a.a = 's'; + this.a.b = 's'; + this.a.c = 's'; + this.a.d = 's'; + this.a.e = 's'; + this.a.f = 's'; + + this.s = { + a: '', + b: '', + c: '', + d: '', + e: '', + f: '' + }; + + const color = this.trial_colors[this.currentTrial]; + this.colors = this.colors_all.concat(color); + this.colors = this.shuffle(this.colors); + + this.c.a = this.colors[0]; + this.c.b = this.colors[1]; + this.c.c = this.colors[2]; + this.c.d = this.colors[3]; + this.c.e = this.colors[4]; + this.c.f = this.colors[5]; + + const align = (Math.floor(Math.random() * 2) + 1) === 1 ? 'm' : 'z'; + const different = (Math.floor(Math.random() * 2) + 1) === 1 ? 'rect' : 'circle'; + const pos = Math.floor(Math.random() * (5 - 0 + 1)) + 0; + const props = ['a', 'b', 'c', 'd', 'e', 'f']; + this.a[props[pos]] = align; + + if (different === 'rect') { + this.s = { + a: 'circle', + b: 'circle', + c: 'circle', + d: 'circle', + e: 'circle', + f: 'circle' + }; + } else { + this.s = { + a: 'rect', + b: 'rect', + c: 'rect', + d: 'rect', + e: 'rect', + f: 'rect' + }; + } + this.s[props[pos]] = different; + this.data.push({ + targetColor: color, + targetLocation: this.colors.indexOf(color) + 1, + targetAlignment: (align === 'z' ? 'horizantal' : 'vertical').toUpperCase(), + actualAnswer: align.toUpperCase(), + userAnswer: '', + probability: 0, + random: 0, + responseTime: 0, + isCorrect: 0, + score: 0 + }); + } + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + let rand = Math.random(); + let points = rand <= this.trial_reward_probs[this.currentTrial] ? 10 : 1; + this.data[this.data.length - 1].probability = this.trial_reward_probs[this.currentTrial]; + this.data[this.data.length - 1].random = rand; + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = points; + this.scoreForSpecificTrial = points; + this.totalScore += points; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + + + shuffle(a) { + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; + } + + +} diff --git a/src/app/pages/experiments/simon-task-final/matrix.ts b/src/app/pages/experiments/simon-task-final/matrix.ts new file mode 100644 index 00000000..49e37abe --- /dev/null +++ b/src/app/pages/experiments/simon-task-final/matrix.ts @@ -0,0 +1,17 @@ +export class Matrix { + rewards: number[] = [ + 39, 56, 90, 72, 63, 63, 23, 16, 23, 26, 82, 83, 88, 78, 76, 13, 62, 86, 89, 91, 87, 48, 78, 66, 64, 30, 41, 66, 29, 26, 7, 35, 34, 41, 32, 58, 85, 87, 90, 62, 72, 20, 20, 14, 15, 21, 28, 16, 60, 20, 37, 47, 78, 58, 45, 35, 43, 37, 51, 61, 39, 93, 91, 68, 68, 58, 94, 93, 90, 64, 76, 39, 71, 87, 51, 91, 83, 68, 67, 54, 79, 66, 84, 44, 47, 86, 8, 44, 53, 24, 58, 24, 24, 23, 19, 7, 26, 36, 17, 21, 12, 21, 34, 14, 80, 92, 44, 72, 87, 40, 81, 93, 85, 93, 79, 39, 19, 57, 44, 15, 11, 46, 71, 51, 35, 34, 60, 61, 69, 82, 68, 7, 18, 6, 25, 37, 67, 64, 76, 18, 67, 69, 92, 69, 91, 49, 49, 20, 29, 34, 38, 20, 47, 49, 36, 91, 75, 51, 58, 61, 32, 43, 14, 21, 10, 42, 29, 42, 59, 79, 68, 36, 76, 93, 78, 52, 88, 60, 69, 35, 59, 42, 39, 25, 90, 90, 76, 72, 82, 81, 52, 20, 17, 25, 38, 50, 37, 67, 72, 41, 75, 79, 86, 86, 72, 81, 69, 61, 32, 29, 81, 17, 68, 53, 23, 19, 37, 53, 47, 55, 56, 49, 53, 66, 69, 44, 40, 66, 59, 25, 23, 17, 32, 54, 47, 17, 9, 34, 38, 20, 16, 21, 40, 28, 18, 35, 71, 43, 40, 83, 63, 92, 76, 32, 14, 15, 18, 13, 16, 40, 25, 26, 22, 63, 49, 56, 94, 81, 66, 49, 68, 58, 55, 44, 61, 63, 48, 16, 27, 35, 9, 7, 10, 31, 43, 46, 50, 93, 84, 38, 29, 45, 21, 30, 52, 40, 37, 24, 40, 79, 37, 5, 86, 91, 66, 74, 68, 35, 77, 88, 61, 18, 39, 65, 44, 23, 56, 10, 25, 46, 47, 21, 50, 25, 13, 28, 38, 68, 75, 66, 94, 91, 41, 33, 32, 47, 49, 83, 62, 84, 83, 73, 77, 26, 21, 50, 73, 47, 32, 44, 46, 38, 66, 55, 49, 13, 19, 43, 68, 62, 22, 14, 33, 22, 64, 44, 39, 87, 22, 67, 86, 86, 59, 92, 69, 14, 50, 30, 15, 29, 39, 25, 10, 32, 51, 79, 58, 42, 24, 5, 13, 51, 17, 34, 64, 22, 25, 25, 49, 47, 28, 59, 61, 45, 5, 14, 14, 32, 33, 10, 77, 60, 61, 36, 29, 16, 26, 35, 15, 21, 7, 13, 58, 33, 16, 61, 60, 70, 83, 59, 19, 81, 70, 72, 76, 88, 67, 77, 62, 83, 81, 86, 81, 82, 94, 78, 66, 87, 86, 80, 56, 53, 80, 71, 47, 64, 94, 68, 41, 16, 56, 42, 51, 83, 84, 79, 87, 69, 82, 43, 23, 55, 32, 11, 6, 64, 72, 58, 17, 65, 69, 93, 80, 54, 34, 85, 48, 58, 94, 56, 41, 49, 48, 90, 83, 61, 33, 8, 14, 12, 23, 17, 29, 32, 24, 26, 53, 48, 39, 48, 30, 12, 45, 85, 34, 37, 65, 63, 18, 9, 92, 60, 12, 24, 47, 62, 20, 43, 40, 42, 54, 38, 28, 19, 30, 38, 48, 52, 31, 39, 55, 37, 45, 56, 73, 44, 35, 34, 54, 16, 40, 92, 88, 68, 75, 51, 41, 36, 47, 76, 41, 70, 75, 62, 57, 52, 60, 89, 11, 53, 72, 92, 83, 58, 69, 53, 66, 80, 48, 36, 44, 60, 66, 56, 11, 52, 30, 36, 15, 19, 74, 21, 58, 73, 20, 18, 22, 13, 11, 29, 32, 73, 73, 61, 47, 26, 64, 88, 80, 82, 54, 33, 8, 5, 20, 70, 92, 59, 57, 32, 66, 22, 34, 41, 39, 45, 41, 24, 74, 65, 20, 21, 41, 70, 70, 7, 24, 48, 94, 74, 81, 58, 82, 58, 36, 69, 90, 55, 22, 84, 17, 15, 10, 8, 17, 16, 56, 15, 31, 48, 14, 14, 54, 46, 68, 73, 92, 69, 24, 31, 46, 44, 44, 55, 42, 24, 11, 23, 19, 27, 42, 24, 27, 10, 17, 13, 8, 10, 27, 43, 60, 75, 92, 92, 38, 31, 10, 5, 29, 13, 47, 18, 48, 69, 69, 68, 93, 84, 89, 55, 45, 53, 50, 19, 44, 10, 21, 12, 28, 26, 65, 53, 87, 79, 66, 87, 32, 29, 25, 23, 7, 5, 57, 83, 44, 41, 21, 21, 6, 52, 56, 42, 44, 43, 45, 55, 82, 89, 93, 70, 52, 70, 45, 58, 34, 47, 63, 17, 37, 13, 13, 59, 28, 61, 40, 47, 72, 74, 85, 33, 35, 14, 9, 53, 7, 11, 24, 7, 25, 88, 88, 91, 59, 25, 22, 34, 39, 52, 10, 28, 27, 48, 42, 54, 13, 16, 16, 20, 5, 18, 43, 63, 61, 44, 52, 29, 9, 72, 80, 11, 48, 49, 20, 37, 5, 36, 50, 32, 49, 17, 38, 22, 49, 80, 56, 53, 33, 38, 12, 83, 61, 71, 72, 54, 69, 37, 64, 25, 22, 53, 32, 40, 46, 25, 15, 21, 38, 59, 89, 58, 93, 84, 90, 72, 59, 79, 91, 91, 37, 23, 38, 11, 22, 28, 44, 48, 82, 87, 80, 77, 63, 89, 82, 87, 92, 66, 49, 38, 17, 30, 39, 56, 21, 22, 44, 26, 46, 59, 66, 23, 12, 8, 26, 36, 56, 61, 58, 58, 55, 80, 64, 90, 64, 70, 76, 51, 45, 71, 49, 69, 70, 17, 20, 54, 74, 70, 67, 77, 82, 36, 21, 14, 14, 31, 29, 13, 12, 14, 61, 77, 78, 87, 77, 80, 33, 41, 28, 37, 84, 61, 65, 53, 61, 52, 62, 86, 74, 79, 31, 46, 35, 5, 61, 87, 92, 75, 76, 74, 77, 78, 56, 19, 38, 41, 20, 41, 70, 43, 55, 84, 57, 74, 65, 85, 45, 34, 7, 23, 29, 43, 30, 65, 63, 42, 64, 87, 86, 67, 89, 73, 88, 90, 86, 46, 57, 38, 34, 56, 33, 8, 38, 75, 45, 45, 66, 68, 11, 32, 54, 71, 81, 62, 59, 94, 51, 51, 31, 36, 15, 29, 35, 33, 65, 50, 36, 50, 49, 44, 46, 63, 43, 7, 44, 62, 65, 59, 63, 53, 77, 14, 67, 6, 64, 74, 35, 37, 26, 45, 23, 44, 25, 40, 30, 13, 9, 37, 62, 63, 27, 8, 17, 15, 75, 63, 59, 66, 56, 66, 37, 33, 59, 84, 81, 76, 82, 52, 81, 87, 50, 65, 63, 74, 19, 32, 42, 17, 62, 83, 84, 59, 72, 78, 70, 5, 27, 90, 47, 73, 56, 32, 66, 67, 50, 56, 56, 54, 80, 67, 44, 37, 27, 13, 24, 22, 30, 81, 68, 92, 71, 72, 68, 47, 36, 37, 54, 27, 47, 53, 94, 74, 71, 17, 54, 34, 70, 47, 94, 66, 31, 35, 82, 74, 62, 55, 72, 54, 58, 50, 31, 69, 28, 56, 66, 63, 50, 76, 86, 37, 31, 43, 40, 20, 40, 48, 30, 60, 36, 48, 57, 61, 36, 17, 25, 76, 68, 35, 53, 46, 59, 29, 16, 26, 27, 23, 61, 76, 72, 40, 14, 7, 21, 5, 14, 23, 58, 94, 69, 82, 42, 35 + ]; + + stim: number[] = [ + 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2 + ]; + + pos: number[] = [ + 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1 + ]; + + iti: number[] = [ + 1227, 1089, 911, 1019, 872, 804, 1160, 924, 989, 1203, 799, 1220, 912, 816, 1008, 785, 836, 807, 897, 1086, 828, 890, 872, 991, 1038, 784, 1097, 773, 1121, 1169, 953, 1115, 800, 993, 1044, 768, 779, 929, 933, 968, 1082, 1141, 1224, 1114, 944, 1197, 1068, 1042, 909, 840, 1175, 814, 976, 1150, 801, 1022, 813, 1218, 983, 1176, 1216, 869, 854, 986, 814, 952, 1179, 910, 1056, 789, 1016, 1074, 995, 1047, 888, 975, 760, 1054, 1029, 1013, 1014, 1042, 1104, 1031, 1180, 884, 1073, 1062, 879, 958, 1123, 1018, 1218, 946, 1024, 1054, 1013, 1094, 784, 859, 957, 922, 1246, 828, 1094, 972, 917, 809, 766, 965, 1226, 1132, 1082, 898, 1157, 1124, 1015, 1211, 866, 894, 1198, 858, 1221, 1150, 1126, 921, 1224, 1042, 1192, 827, 926, 1175, 923, 1141, 1015, 783, 1213, 1198, 902, 1115, 955, 772, 1185, 1074, 1060, 813, 824, 1236, 868, 985, 856, 980, 980, 1034, 835, 956, 777, 785, 971, 1096, 1090, 1143, 754, 790, 940, 906, 1063, 964, 985, 1156, 798, 1037, 821, 1100, 779, 958, 898, 833, 1091, 1041, 796, 765, 1019, 1145, 1087, 823, 818, 985, 1069, 892, 841, 966, 1170, 1171, 797, 1126, 920, 775, 845, 816, 1161, 988, 1100, 786, 890, 1200, 914, 1122, 1061, 859, 1005, 797, 829, 1159, 951, 1207, 1054, 1194, 957, 761, 816, 891, 1013, 1113, 1144, 854, 1040, 806, 783, 1061, 1022, 791, 1014, 1221, 790, 945, 1213, 839, 772, 1147, 854, 837, 1164, 814, 1179, 782, 1029, 1102, 1007, 1152, 1100, 1150, 903, 780, 850, 855, 1235, 904, 1198, 1233, 972, 992, 792, 750, 911, 1209, 859, 1203, 1185, 768, 985, 924, 1248, 1086, 1117, 780, 832, 917, 1229, 918, 761, 998, 980, 1152, 828, 1076, 1179, 1176, 879, 921, 765, 772, 1093, 763, 789, 792, 1226, 1102, 814, 762, 1145, 1080, 945, 1203, 876, 1091, 1146, 1233, 912, 751, 935, 942, 916, 1161, 888, 1234, 1041, 1160, 1167, 1056, 1136, 786, 788, 754, 945, 794, 854, 923, 1162, 1061, 930, 943, 1212, 997, 1206, 1008, 895, 993, 1055, 1079, 809, 963, 1126, 848, 868, 1041, 957, 1170, 1229, 1131, 947, 860, 1132, 1191, 1187, 1220, 778, 902, 1173, 1018, 1077, 1078, 964, 896, 781, 1091, 888, 1138, 877, 755, 1173, 899, 861, 834, 769, 1231, 761, 1043, 1134, 915, 807, 1168, 1236, 754, 882, 851, 1131, 905, 953, 1074, 873, 1200, 1029, 916, 1160, 1235, 994, 1175, 961, 1184, 979, 1108, 1176, 1118, 861, 1137, 931, 771, 1165, 979, 1091, 839, 1244, 817, 1055, 827, 935, 1079, 1073, 1201, 1088, 909, 930, 1154, 1121, 1178, 1191, 1084, 1163, 1146, 1216, 760, 1189, 820, 1243, 847, 823, 1055, 1171, 847, 1019, 1106, 965, 798, 1114, 887, 1019, 1125, 823, 1012, 1129, 904, 1241, 946, 1220, 1000, 1056, 1093, 1090, 886, 829, 998, 1149, 1138, 1040, 1238, 1036, 1054, 775, 1130, 1207, 1191, 791, 1000, 836, 994, 1049, 1154, 854, 1118, 1104, 1175, 1106, 1007, 916, 923, 831, 976, 1095, 1206, 1040, 822, 818, 1098, 779, 759, 975, 1210, 1154, 844, 1225, 832, 1134, 847, 755, 1095, 857, 807, 886, 784, 1166, 1170, 1204, 754, 988, 972, 1147, 1183, 1123, 1166, 1240, 1045, 783, 779, 1235, 1060, 865, 852, 1123, 977, 823, 994, 1111, 1100, 1077, 1230, 962, 982, 1018, 829, 1226, 911, 1035, 779, 855, 814, 880, 1115, 825, 883, 1144, 771, 821, 929, 895, 1011, 910, 877, 1187, 1240, 983, 1102, 969, 1220, 1237, 1174, 922, 1191, 758, 786, 878, 1116, 1092, 1080, 883, 1132, 892, 1125, 751, 1026, 928, 786, 933, 1108, 889, 942, 908, 921, 1058, 1030, 860, 937, 991, 907, 956, 1157, 1038, 1037, 974, 835, 946, 1048, 1010, 896, 1167, 1014, 1240, 1031, 874, 772, 823, 862, 856, 936, 1068, 834, 757, 1247, 1068, 1036, 906, 1078, 1219, 1144, 856, 1234, 893, 973, 913, 848, 1073, 782, 948, 756, 1231, 1018, 1037, 1241, 859, 1198, 1061, 1203, 1074, 962, 1023, 889, 1156, 1039, 890, 1226, 967, 1212, 1053, 1181, 1217, 841, 891, 1051, 1093, 970, 1203, 805, 764, 779, 935, 939, 796, 884, 1217, 1181, 1181, 779, 1036, 1081, 847, 783, 1124, 1101, 1003, 1066, 795, 1248, 800, 1072, 1152, 814, 882, 1051, 1131, 1008, 898, 1082, 1011, 1208, 1147, 1090, 806, 825, 1116, 820, 1112, 938, 794, 960, 756, 837, 957, 1086, 764, 1041, 752, 771, 1202, 1003, 888, 1206, 799, 1152, 794, 1224, 913, 1026, 1154, 1153, 1010, 1245, 1160, 827, 1121, 889, 1165, 1106, 771, 979, 1118, 855, 1225, 1059, 1222, 812, 1044, 827, 994, 759, 1113, 835, 796, 989, 1168, 1071, 1102, 1215, 921, 947, 904, 1100, 963, 1004, 1007, 927, 947, 1134, 802, 1031, 1144, 769, 1018, 763, 899, 943, 942, 1143, 794, 959, 1206, 1137, 1180, 1234, 1192, 912, 930, 850, 958, 863, 1167, 996, 752, 1108, 830, 796, 960, 1186, 1121, 1196, 1102, 1012, 1247, 941, 1118, 946, 909, 1205, 870, 1208, 822, 1035, 1186, 928, 1093, 866, 1209, 1220, 1004, 1073, 930, 947, 1042, 792, 864, 978, 1116, 978, 769, 1027, 1006, 932, 765, 1048, 1226, 842, 859, 1134, 1022, 1117, 1184, 1209, 1027, 1042, 792, 1001, 1076, 1201, 1012, 996, 1016, 804, 803, 1019, 1205, 873, 1125, 876, 1110, 925, 801, 833, 777, 1016, 869, 1028, 1221, 833, 1236, 1205, 897, 1220, 1123, 996, 1020, 1135, 1105, 1029, 839, 836, 981, 819, 970, 1185, 961, 1138, 993, 792, 942, 831, 915, 823, 900, 1093, 1206, 1097, 962, 759, 802, 1169, 778, 932, 866, 1219, 1082, 1168, 899, 1173, 1181, 907, 1221, 858, 1207, 1037, 1040, 1127, 1092, 1151, 1210, 1135, 1209, 775, 851, 984, 886, 1044, 811, 970, 864, 1111, 875, 1196, 1000, 1222, 1180, 1068, 1006, 1136, 1099, 1177, 1207, 781, 1242, 1014, 802, 1197, 789, 1149, 1144, 1168, 828, 1092, 1091, 842, 1171, 896, 1101, 941, 867, 1005, 1044, 940, 1206, 904, 878, 1147, 921, 1079, 925, 928, 1231, 1218, 944, 911, 1222, 1153, 781, 1137, 1218, 1104, 1034, 1037, 944, 1119, 809, 1186, 1140, 1022, 951, 851, 1124, 789, 1157, 892, 1172, 1132, 924, 1081, 921, 1138, 1200, 1191, 1160, 836, 770, 1244, 864, 1122, 997, 1213, 809, 1183, 854, 1096, 954, 757, 1090, 914, 1127, 902, 944, 1207, 1185, 1248, 936, 847, 1012, 810, 897, 1160, 861, 1179, 882, 847, 1089, 778, 1223, 1238, 1176, 919, 1119, 961, 863, 963, 1056, 836, 1155, 1229, 800, 1102, 865, 972, 1204, 984, 1002, 795, 989, 1204, 1009, 1168, 875, 1051, 758, 929, 1066, 866, 1191, 1150, 1112, 898, 1037, 1189, 870, 1163, 1008, 1232, 781, 851, 835, 1200, 797, 769, 827, 1101, 1155, 1080, 1031, 1221, 1201, 1140, 798, 1177, 1013, 906, 910, 934, 815, 1068, 1201, 1146, 1125, 1096, 1056, 1141, 844, 1230, 857, 1167, 1117, 909, 1100, 945, 1097, 800, 861, 929, 1228, 1001, 1119, 899, 1228, 1194, 814, 865, 871, 1141, 1237, 1056, 838, 1009, 1205, 1099, 925, 988, 1050, 828, 1163, 1044, 1000, 811, 1081, 974, 869, 1011, 1129, 941, 772, 856, 993, 1134, 753, 1129, 945, 968, 806, 773, 1070, 1184, 780, 1102, 1000, 967, 765, 1169, 1018, 985, 834, 1198, 1083, 995, 804, 961, 1050, 1246, 1102, 821, 1127, 807, 1219, 926, 1168, 823, 1050, 795, 873, 1125, 873, 1175, 935, 890, 947, 947, 993, 825, 967, 856, 1149, 1178, 877, 1141, 1177, 969, 753, 780, 909, 962 + ]; +} \ No newline at end of file diff --git a/src/app/pages/experiments/simon-task-final/simon-task-final.component.html b/src/app/pages/experiments/simon-task-final/simon-task-final.component.html new file mode 100644 index 00000000..52bbc484 --- /dev/null +++ b/src/app/pages/experiments/simon-task-final/simon-task-final.component.html @@ -0,0 +1,382 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Simon Task (Rewarded)

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ This is a continuation of the previous game. +
+ +
+ Each turn, before you see a circle, you will see how much money you can earn for a correct + answer. +
+ +
+ For example, if you see +25 and you answer correctly, you WIN 25 cents. +
+ +
+ The amount you can win will change from turn to turn. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Remember, your task is to press the "Z" key if the circle shown is in GREEN + or press + the "M" key if the circle is in ORANGE. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ + + +
+
+
+
+ add +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn reward for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, your task is to press the "Z" key if the circle shown is in GREEN + or press + the "M" key if the circle is in ORANGE. +
+ + +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ + + +
+
+
+
+ add +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/simon-task-final/simon-task-final.component.scss b/src/app/pages/experiments/simon-task-final/simon-task-final.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/simon-task-final/simon-task-final.component.ts b/src/app/pages/experiments/simon-task-final/simon-task-final.component.ts new file mode 100644 index 00000000..c970a2ed --- /dev/null +++ b/src/app/pages/experiments/simon-task-final/simon-task-final.component.ts @@ -0,0 +1,372 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +import { Matrix } from './matrix'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-simon-task-final', + templateUrl: './simon-task-final.component.html', + styleUrls: ['./simon-task-final.component.scss'] +}) +export class SimonTaskFinalComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 2; + maxResponseTime: number = 800; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 10; + actualTrials: number = 30; + + step: number = 1; + color_a: string = ''; + color_b: string = ''; + currentReward: number = 0; + showReward: boolean = false; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + currentReward: number, + actualAnswer: string, + position: string, + compatible: boolean, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + matrix = new Matrix(); + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (event.key === 'Z' || event.key === 'z') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'Z'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else if (event.key === 'M' || event.key === 'm') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'M'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'INVALID'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + + + this.showReward = false; + this.currentTrial += 1; + this.generateStimulus(); + this.showReward = true; + await this.wait(500); + this.showReward = false; + await this.wait(250); + + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + + generateStimulus() { + const random = this.matrix.stim[this.currentTrial - 1]; + const random2 = this.matrix.pos[this.currentTrial - 1]; + this.currentReward = this.matrix.rewards[this.currentTrial - 1]; + + let color = 'green'; + if (random === 1) { + color = 'green'; + } else { + color = 'orange'; + } + + if (random2 === 1) { + this.color_a = color; + this.color_b = 'transparent'; + } else { + this.color_b = color; + this.color_a = 'transparent'; + } + + this.data.push({ + actualAnswer: color === 'green' ? 'Z' : 'M', + currentReward: this.currentReward, + position: random2 === 1 ? 'LEFT' : 'RIGHT', + compatible: ((random2 === 1) && (color === 'green')) || ((random2 === 2) && (color === 'orange')), + userAnswer: '', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = this.data[this.data.length - 1].currentReward; + this.scoreForSpecificTrial = this.data[this.data.length - 1].currentReward; + this.totalScore += this.data[this.data.length - 1].currentReward; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color_a = ''; + this.color_b = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/simon-task-prelim/matrix.ts b/src/app/pages/experiments/simon-task-prelim/matrix.ts new file mode 100644 index 00000000..49e37abe --- /dev/null +++ b/src/app/pages/experiments/simon-task-prelim/matrix.ts @@ -0,0 +1,17 @@ +export class Matrix { + rewards: number[] = [ + 39, 56, 90, 72, 63, 63, 23, 16, 23, 26, 82, 83, 88, 78, 76, 13, 62, 86, 89, 91, 87, 48, 78, 66, 64, 30, 41, 66, 29, 26, 7, 35, 34, 41, 32, 58, 85, 87, 90, 62, 72, 20, 20, 14, 15, 21, 28, 16, 60, 20, 37, 47, 78, 58, 45, 35, 43, 37, 51, 61, 39, 93, 91, 68, 68, 58, 94, 93, 90, 64, 76, 39, 71, 87, 51, 91, 83, 68, 67, 54, 79, 66, 84, 44, 47, 86, 8, 44, 53, 24, 58, 24, 24, 23, 19, 7, 26, 36, 17, 21, 12, 21, 34, 14, 80, 92, 44, 72, 87, 40, 81, 93, 85, 93, 79, 39, 19, 57, 44, 15, 11, 46, 71, 51, 35, 34, 60, 61, 69, 82, 68, 7, 18, 6, 25, 37, 67, 64, 76, 18, 67, 69, 92, 69, 91, 49, 49, 20, 29, 34, 38, 20, 47, 49, 36, 91, 75, 51, 58, 61, 32, 43, 14, 21, 10, 42, 29, 42, 59, 79, 68, 36, 76, 93, 78, 52, 88, 60, 69, 35, 59, 42, 39, 25, 90, 90, 76, 72, 82, 81, 52, 20, 17, 25, 38, 50, 37, 67, 72, 41, 75, 79, 86, 86, 72, 81, 69, 61, 32, 29, 81, 17, 68, 53, 23, 19, 37, 53, 47, 55, 56, 49, 53, 66, 69, 44, 40, 66, 59, 25, 23, 17, 32, 54, 47, 17, 9, 34, 38, 20, 16, 21, 40, 28, 18, 35, 71, 43, 40, 83, 63, 92, 76, 32, 14, 15, 18, 13, 16, 40, 25, 26, 22, 63, 49, 56, 94, 81, 66, 49, 68, 58, 55, 44, 61, 63, 48, 16, 27, 35, 9, 7, 10, 31, 43, 46, 50, 93, 84, 38, 29, 45, 21, 30, 52, 40, 37, 24, 40, 79, 37, 5, 86, 91, 66, 74, 68, 35, 77, 88, 61, 18, 39, 65, 44, 23, 56, 10, 25, 46, 47, 21, 50, 25, 13, 28, 38, 68, 75, 66, 94, 91, 41, 33, 32, 47, 49, 83, 62, 84, 83, 73, 77, 26, 21, 50, 73, 47, 32, 44, 46, 38, 66, 55, 49, 13, 19, 43, 68, 62, 22, 14, 33, 22, 64, 44, 39, 87, 22, 67, 86, 86, 59, 92, 69, 14, 50, 30, 15, 29, 39, 25, 10, 32, 51, 79, 58, 42, 24, 5, 13, 51, 17, 34, 64, 22, 25, 25, 49, 47, 28, 59, 61, 45, 5, 14, 14, 32, 33, 10, 77, 60, 61, 36, 29, 16, 26, 35, 15, 21, 7, 13, 58, 33, 16, 61, 60, 70, 83, 59, 19, 81, 70, 72, 76, 88, 67, 77, 62, 83, 81, 86, 81, 82, 94, 78, 66, 87, 86, 80, 56, 53, 80, 71, 47, 64, 94, 68, 41, 16, 56, 42, 51, 83, 84, 79, 87, 69, 82, 43, 23, 55, 32, 11, 6, 64, 72, 58, 17, 65, 69, 93, 80, 54, 34, 85, 48, 58, 94, 56, 41, 49, 48, 90, 83, 61, 33, 8, 14, 12, 23, 17, 29, 32, 24, 26, 53, 48, 39, 48, 30, 12, 45, 85, 34, 37, 65, 63, 18, 9, 92, 60, 12, 24, 47, 62, 20, 43, 40, 42, 54, 38, 28, 19, 30, 38, 48, 52, 31, 39, 55, 37, 45, 56, 73, 44, 35, 34, 54, 16, 40, 92, 88, 68, 75, 51, 41, 36, 47, 76, 41, 70, 75, 62, 57, 52, 60, 89, 11, 53, 72, 92, 83, 58, 69, 53, 66, 80, 48, 36, 44, 60, 66, 56, 11, 52, 30, 36, 15, 19, 74, 21, 58, 73, 20, 18, 22, 13, 11, 29, 32, 73, 73, 61, 47, 26, 64, 88, 80, 82, 54, 33, 8, 5, 20, 70, 92, 59, 57, 32, 66, 22, 34, 41, 39, 45, 41, 24, 74, 65, 20, 21, 41, 70, 70, 7, 24, 48, 94, 74, 81, 58, 82, 58, 36, 69, 90, 55, 22, 84, 17, 15, 10, 8, 17, 16, 56, 15, 31, 48, 14, 14, 54, 46, 68, 73, 92, 69, 24, 31, 46, 44, 44, 55, 42, 24, 11, 23, 19, 27, 42, 24, 27, 10, 17, 13, 8, 10, 27, 43, 60, 75, 92, 92, 38, 31, 10, 5, 29, 13, 47, 18, 48, 69, 69, 68, 93, 84, 89, 55, 45, 53, 50, 19, 44, 10, 21, 12, 28, 26, 65, 53, 87, 79, 66, 87, 32, 29, 25, 23, 7, 5, 57, 83, 44, 41, 21, 21, 6, 52, 56, 42, 44, 43, 45, 55, 82, 89, 93, 70, 52, 70, 45, 58, 34, 47, 63, 17, 37, 13, 13, 59, 28, 61, 40, 47, 72, 74, 85, 33, 35, 14, 9, 53, 7, 11, 24, 7, 25, 88, 88, 91, 59, 25, 22, 34, 39, 52, 10, 28, 27, 48, 42, 54, 13, 16, 16, 20, 5, 18, 43, 63, 61, 44, 52, 29, 9, 72, 80, 11, 48, 49, 20, 37, 5, 36, 50, 32, 49, 17, 38, 22, 49, 80, 56, 53, 33, 38, 12, 83, 61, 71, 72, 54, 69, 37, 64, 25, 22, 53, 32, 40, 46, 25, 15, 21, 38, 59, 89, 58, 93, 84, 90, 72, 59, 79, 91, 91, 37, 23, 38, 11, 22, 28, 44, 48, 82, 87, 80, 77, 63, 89, 82, 87, 92, 66, 49, 38, 17, 30, 39, 56, 21, 22, 44, 26, 46, 59, 66, 23, 12, 8, 26, 36, 56, 61, 58, 58, 55, 80, 64, 90, 64, 70, 76, 51, 45, 71, 49, 69, 70, 17, 20, 54, 74, 70, 67, 77, 82, 36, 21, 14, 14, 31, 29, 13, 12, 14, 61, 77, 78, 87, 77, 80, 33, 41, 28, 37, 84, 61, 65, 53, 61, 52, 62, 86, 74, 79, 31, 46, 35, 5, 61, 87, 92, 75, 76, 74, 77, 78, 56, 19, 38, 41, 20, 41, 70, 43, 55, 84, 57, 74, 65, 85, 45, 34, 7, 23, 29, 43, 30, 65, 63, 42, 64, 87, 86, 67, 89, 73, 88, 90, 86, 46, 57, 38, 34, 56, 33, 8, 38, 75, 45, 45, 66, 68, 11, 32, 54, 71, 81, 62, 59, 94, 51, 51, 31, 36, 15, 29, 35, 33, 65, 50, 36, 50, 49, 44, 46, 63, 43, 7, 44, 62, 65, 59, 63, 53, 77, 14, 67, 6, 64, 74, 35, 37, 26, 45, 23, 44, 25, 40, 30, 13, 9, 37, 62, 63, 27, 8, 17, 15, 75, 63, 59, 66, 56, 66, 37, 33, 59, 84, 81, 76, 82, 52, 81, 87, 50, 65, 63, 74, 19, 32, 42, 17, 62, 83, 84, 59, 72, 78, 70, 5, 27, 90, 47, 73, 56, 32, 66, 67, 50, 56, 56, 54, 80, 67, 44, 37, 27, 13, 24, 22, 30, 81, 68, 92, 71, 72, 68, 47, 36, 37, 54, 27, 47, 53, 94, 74, 71, 17, 54, 34, 70, 47, 94, 66, 31, 35, 82, 74, 62, 55, 72, 54, 58, 50, 31, 69, 28, 56, 66, 63, 50, 76, 86, 37, 31, 43, 40, 20, 40, 48, 30, 60, 36, 48, 57, 61, 36, 17, 25, 76, 68, 35, 53, 46, 59, 29, 16, 26, 27, 23, 61, 76, 72, 40, 14, 7, 21, 5, 14, 23, 58, 94, 69, 82, 42, 35 + ]; + + stim: number[] = [ + 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2 + ]; + + pos: number[] = [ + 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1 + ]; + + iti: number[] = [ + 1227, 1089, 911, 1019, 872, 804, 1160, 924, 989, 1203, 799, 1220, 912, 816, 1008, 785, 836, 807, 897, 1086, 828, 890, 872, 991, 1038, 784, 1097, 773, 1121, 1169, 953, 1115, 800, 993, 1044, 768, 779, 929, 933, 968, 1082, 1141, 1224, 1114, 944, 1197, 1068, 1042, 909, 840, 1175, 814, 976, 1150, 801, 1022, 813, 1218, 983, 1176, 1216, 869, 854, 986, 814, 952, 1179, 910, 1056, 789, 1016, 1074, 995, 1047, 888, 975, 760, 1054, 1029, 1013, 1014, 1042, 1104, 1031, 1180, 884, 1073, 1062, 879, 958, 1123, 1018, 1218, 946, 1024, 1054, 1013, 1094, 784, 859, 957, 922, 1246, 828, 1094, 972, 917, 809, 766, 965, 1226, 1132, 1082, 898, 1157, 1124, 1015, 1211, 866, 894, 1198, 858, 1221, 1150, 1126, 921, 1224, 1042, 1192, 827, 926, 1175, 923, 1141, 1015, 783, 1213, 1198, 902, 1115, 955, 772, 1185, 1074, 1060, 813, 824, 1236, 868, 985, 856, 980, 980, 1034, 835, 956, 777, 785, 971, 1096, 1090, 1143, 754, 790, 940, 906, 1063, 964, 985, 1156, 798, 1037, 821, 1100, 779, 958, 898, 833, 1091, 1041, 796, 765, 1019, 1145, 1087, 823, 818, 985, 1069, 892, 841, 966, 1170, 1171, 797, 1126, 920, 775, 845, 816, 1161, 988, 1100, 786, 890, 1200, 914, 1122, 1061, 859, 1005, 797, 829, 1159, 951, 1207, 1054, 1194, 957, 761, 816, 891, 1013, 1113, 1144, 854, 1040, 806, 783, 1061, 1022, 791, 1014, 1221, 790, 945, 1213, 839, 772, 1147, 854, 837, 1164, 814, 1179, 782, 1029, 1102, 1007, 1152, 1100, 1150, 903, 780, 850, 855, 1235, 904, 1198, 1233, 972, 992, 792, 750, 911, 1209, 859, 1203, 1185, 768, 985, 924, 1248, 1086, 1117, 780, 832, 917, 1229, 918, 761, 998, 980, 1152, 828, 1076, 1179, 1176, 879, 921, 765, 772, 1093, 763, 789, 792, 1226, 1102, 814, 762, 1145, 1080, 945, 1203, 876, 1091, 1146, 1233, 912, 751, 935, 942, 916, 1161, 888, 1234, 1041, 1160, 1167, 1056, 1136, 786, 788, 754, 945, 794, 854, 923, 1162, 1061, 930, 943, 1212, 997, 1206, 1008, 895, 993, 1055, 1079, 809, 963, 1126, 848, 868, 1041, 957, 1170, 1229, 1131, 947, 860, 1132, 1191, 1187, 1220, 778, 902, 1173, 1018, 1077, 1078, 964, 896, 781, 1091, 888, 1138, 877, 755, 1173, 899, 861, 834, 769, 1231, 761, 1043, 1134, 915, 807, 1168, 1236, 754, 882, 851, 1131, 905, 953, 1074, 873, 1200, 1029, 916, 1160, 1235, 994, 1175, 961, 1184, 979, 1108, 1176, 1118, 861, 1137, 931, 771, 1165, 979, 1091, 839, 1244, 817, 1055, 827, 935, 1079, 1073, 1201, 1088, 909, 930, 1154, 1121, 1178, 1191, 1084, 1163, 1146, 1216, 760, 1189, 820, 1243, 847, 823, 1055, 1171, 847, 1019, 1106, 965, 798, 1114, 887, 1019, 1125, 823, 1012, 1129, 904, 1241, 946, 1220, 1000, 1056, 1093, 1090, 886, 829, 998, 1149, 1138, 1040, 1238, 1036, 1054, 775, 1130, 1207, 1191, 791, 1000, 836, 994, 1049, 1154, 854, 1118, 1104, 1175, 1106, 1007, 916, 923, 831, 976, 1095, 1206, 1040, 822, 818, 1098, 779, 759, 975, 1210, 1154, 844, 1225, 832, 1134, 847, 755, 1095, 857, 807, 886, 784, 1166, 1170, 1204, 754, 988, 972, 1147, 1183, 1123, 1166, 1240, 1045, 783, 779, 1235, 1060, 865, 852, 1123, 977, 823, 994, 1111, 1100, 1077, 1230, 962, 982, 1018, 829, 1226, 911, 1035, 779, 855, 814, 880, 1115, 825, 883, 1144, 771, 821, 929, 895, 1011, 910, 877, 1187, 1240, 983, 1102, 969, 1220, 1237, 1174, 922, 1191, 758, 786, 878, 1116, 1092, 1080, 883, 1132, 892, 1125, 751, 1026, 928, 786, 933, 1108, 889, 942, 908, 921, 1058, 1030, 860, 937, 991, 907, 956, 1157, 1038, 1037, 974, 835, 946, 1048, 1010, 896, 1167, 1014, 1240, 1031, 874, 772, 823, 862, 856, 936, 1068, 834, 757, 1247, 1068, 1036, 906, 1078, 1219, 1144, 856, 1234, 893, 973, 913, 848, 1073, 782, 948, 756, 1231, 1018, 1037, 1241, 859, 1198, 1061, 1203, 1074, 962, 1023, 889, 1156, 1039, 890, 1226, 967, 1212, 1053, 1181, 1217, 841, 891, 1051, 1093, 970, 1203, 805, 764, 779, 935, 939, 796, 884, 1217, 1181, 1181, 779, 1036, 1081, 847, 783, 1124, 1101, 1003, 1066, 795, 1248, 800, 1072, 1152, 814, 882, 1051, 1131, 1008, 898, 1082, 1011, 1208, 1147, 1090, 806, 825, 1116, 820, 1112, 938, 794, 960, 756, 837, 957, 1086, 764, 1041, 752, 771, 1202, 1003, 888, 1206, 799, 1152, 794, 1224, 913, 1026, 1154, 1153, 1010, 1245, 1160, 827, 1121, 889, 1165, 1106, 771, 979, 1118, 855, 1225, 1059, 1222, 812, 1044, 827, 994, 759, 1113, 835, 796, 989, 1168, 1071, 1102, 1215, 921, 947, 904, 1100, 963, 1004, 1007, 927, 947, 1134, 802, 1031, 1144, 769, 1018, 763, 899, 943, 942, 1143, 794, 959, 1206, 1137, 1180, 1234, 1192, 912, 930, 850, 958, 863, 1167, 996, 752, 1108, 830, 796, 960, 1186, 1121, 1196, 1102, 1012, 1247, 941, 1118, 946, 909, 1205, 870, 1208, 822, 1035, 1186, 928, 1093, 866, 1209, 1220, 1004, 1073, 930, 947, 1042, 792, 864, 978, 1116, 978, 769, 1027, 1006, 932, 765, 1048, 1226, 842, 859, 1134, 1022, 1117, 1184, 1209, 1027, 1042, 792, 1001, 1076, 1201, 1012, 996, 1016, 804, 803, 1019, 1205, 873, 1125, 876, 1110, 925, 801, 833, 777, 1016, 869, 1028, 1221, 833, 1236, 1205, 897, 1220, 1123, 996, 1020, 1135, 1105, 1029, 839, 836, 981, 819, 970, 1185, 961, 1138, 993, 792, 942, 831, 915, 823, 900, 1093, 1206, 1097, 962, 759, 802, 1169, 778, 932, 866, 1219, 1082, 1168, 899, 1173, 1181, 907, 1221, 858, 1207, 1037, 1040, 1127, 1092, 1151, 1210, 1135, 1209, 775, 851, 984, 886, 1044, 811, 970, 864, 1111, 875, 1196, 1000, 1222, 1180, 1068, 1006, 1136, 1099, 1177, 1207, 781, 1242, 1014, 802, 1197, 789, 1149, 1144, 1168, 828, 1092, 1091, 842, 1171, 896, 1101, 941, 867, 1005, 1044, 940, 1206, 904, 878, 1147, 921, 1079, 925, 928, 1231, 1218, 944, 911, 1222, 1153, 781, 1137, 1218, 1104, 1034, 1037, 944, 1119, 809, 1186, 1140, 1022, 951, 851, 1124, 789, 1157, 892, 1172, 1132, 924, 1081, 921, 1138, 1200, 1191, 1160, 836, 770, 1244, 864, 1122, 997, 1213, 809, 1183, 854, 1096, 954, 757, 1090, 914, 1127, 902, 944, 1207, 1185, 1248, 936, 847, 1012, 810, 897, 1160, 861, 1179, 882, 847, 1089, 778, 1223, 1238, 1176, 919, 1119, 961, 863, 963, 1056, 836, 1155, 1229, 800, 1102, 865, 972, 1204, 984, 1002, 795, 989, 1204, 1009, 1168, 875, 1051, 758, 929, 1066, 866, 1191, 1150, 1112, 898, 1037, 1189, 870, 1163, 1008, 1232, 781, 851, 835, 1200, 797, 769, 827, 1101, 1155, 1080, 1031, 1221, 1201, 1140, 798, 1177, 1013, 906, 910, 934, 815, 1068, 1201, 1146, 1125, 1096, 1056, 1141, 844, 1230, 857, 1167, 1117, 909, 1100, 945, 1097, 800, 861, 929, 1228, 1001, 1119, 899, 1228, 1194, 814, 865, 871, 1141, 1237, 1056, 838, 1009, 1205, 1099, 925, 988, 1050, 828, 1163, 1044, 1000, 811, 1081, 974, 869, 1011, 1129, 941, 772, 856, 993, 1134, 753, 1129, 945, 968, 806, 773, 1070, 1184, 780, 1102, 1000, 967, 765, 1169, 1018, 985, 834, 1198, 1083, 995, 804, 961, 1050, 1246, 1102, 821, 1127, 807, 1219, 926, 1168, 823, 1050, 795, 873, 1125, 873, 1175, 935, 890, 947, 947, 993, 825, 967, 856, 1149, 1178, 877, 1141, 1177, 969, 753, 780, 909, 962 + ]; +} \ No newline at end of file diff --git a/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.html b/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.html new file mode 100644 index 00000000..f4a91ae2 --- /dev/null +++ b/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.html @@ -0,0 +1,376 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Simon Task (Prelim)

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ During the experiment, you will be shown a circle, either in GREEN or in + ORANGE color. +
+ +
+ Your task is to press the "Z" key if the circle shown is in GREEN + or press + the "M" key if the circle is in ORANGE. +
+ +
+ To do this task successfully you need to IGNORE the position of the circle on the screen. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Put your index fingers in position. +
+ +
+ You will not have very much time so you need to respond as accurately and quickly as + possible. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ add +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, your task is to press the "Z" key if the circle shown is in GREEN + or press + the "M" key if the circle is in ORANGE. +
+ + +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+
+ add +
+
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.scss b/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.ts b/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.ts new file mode 100644 index 00000000..6938dbab --- /dev/null +++ b/src/app/pages/experiments/simon-task-prelim/simon-task-prelim.component.ts @@ -0,0 +1,359 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +import { Matrix } from './matrix'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-simon-task-prelim', + templateUrl: './simon-task-prelim.component.html', + styleUrls: ['./simon-task-prelim.component.scss'] +}) +export class SimonTaskPrelimComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 2; + maxResponseTime: number = 800; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 10; + actualTrials: number = 30; + + step: number = 1; + color_a: string = ''; + color_b: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + actualAnswer: string, + position: string, + compatible: boolean, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + matrix = new Matrix(); + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (event.key === 'Z' || event.key === 'z') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'Z'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else if (event.key === 'M' || event.key === 'm') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'M'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'INVALID'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + + generateStimulus() { + const random = this.matrix.stim[this.currentTrial - 1]; + const random2 = this.matrix.pos[this.currentTrial - 1]; + + let color = 'green'; + if (random === 1) { + color = 'green'; + } else { + color = 'orange'; + } + + if (random2 === 1) { + this.color_a = color; + this.color_b = 'transparent'; + } else { + this.color_b = color; + this.color_a = 'transparent'; + } + + this.data.push({ + actualAnswer: color === 'green' ? 'Z' : 'M', + position: random2 === 1 ? 'LEFT' : 'RIGHT', + compatible: ((random2 === 1) && (color === 'green')) || ((random2 === 2) && (color === 'orange')), + userAnswer: '', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color_a = ''; + this.color_b = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/smiley-face/smiley-face.component.html b/src/app/pages/experiments/smiley-face/smiley-face.component.html new file mode 100644 index 00000000..7b9c33f8 --- /dev/null +++ b/src/app/pages/experiments/smiley-face/smiley-face.component.html @@ -0,0 +1,368 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Smiley Face Game

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ During the experiment, you will be shown an emoji, either with a short mouth or a long mouth +
+ +
+ Your task is to press the "Z" key if the emoji shown has a short mouth and press the 'M' key if the emoji shown has a long mouth +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Put your index fingers in position. +
+ +
+ You will not have very much time so you need to respond as accurately and quickly as + possible. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Remember, Your task is to press the "Z" key if the emoji shown has a short mouth and press the 'M' key if the emoji shown has a long mouth +
+ + +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/smiley-face/smiley-face.component.scss b/src/app/pages/experiments/smiley-face/smiley-face.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/smiley-face/smiley-face.component.ts b/src/app/pages/experiments/smiley-face/smiley-face.component.ts new file mode 100644 index 00000000..2593c9dd --- /dev/null +++ b/src/app/pages/experiments/smiley-face/smiley-face.component.ts @@ -0,0 +1,334 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-smiley-face', + templateUrl: './smiley-face.component.html', + styleUrls: ['./smiley-face.component.scss'] +}) +export class SmileyFaceComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = true; + showScoreAfterEveryTrial: boolean | number = true; + numberOfBreaks: number = 2; + maxResponseTime: number = 800; // In milliseconds + durationOfFeedback: number = 1750; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 30; + actualTrials: number = 300; + + step: number = 1; + size: string = 'no'; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + actualAnswer: string, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (event.key === 'Z' || event.key === 'z') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'Z'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else if (event.key === 'M' || event.key === 'm') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'M'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'INVALID'; + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial + this.numberOfBreaks = currentExperiment.numberOfBreaks + this.maxResponseTime = currentExperiment.maxResponseTime + this.durationOfFeedback = currentExperiment.durationOfFeedback + this.interTrialDelay = currentExperiment.interTrialDelay + this.practiceTrials = currentExperiment.practiceTrials + this.actualTrials = currentExperiment.actualTrials + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + this.isStimulus = true; + this.size = 'no'; + await this.wait(500); + + this.currentTrial += 1; + this.generateStimulus(); + + await this.wait(100); + this.size = 'no'; + + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + } + + + + generateStimulus() { + + this.size = Math.random() > 0.5 ? 'short': 'long'; + + this.data.push({ + actualAnswer: this.size === 'short' ? 'Z' : 'M', + userAnswer: '', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.size = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/stroop-task/stimuli_1_1.ts b/src/app/pages/experiments/stroop-task/stimuli_1_1.ts new file mode 100644 index 00000000..e404e063 --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stimuli_1_1.ts @@ -0,0 +1,722 @@ +export const set = [ + { + "trial": 1, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 2, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 3, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 4, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 5, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 6, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 7, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 8, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 9, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 10, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 11, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 12, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 13, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 14, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 15, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 16, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 17, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 18, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 19, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 20, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 21, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 22, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 23, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 24, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 25, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 26, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 27, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 28, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 29, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 30, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 31, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 32, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 33, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 34, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 35, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 36, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 37, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 38, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 39, + "color": "green", + "congruent": 1, + "word": "blue" + }, + { + "trial": 40, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 41, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 42, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 43, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 44, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 45, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 46, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 47, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 48, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 49, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 50, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 51, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 52, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 53, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 54, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 55, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 56, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 57, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 58, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 59, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 60, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 61, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 62, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 63, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 64, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 65, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 66, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 67, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 68, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 69, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 70, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 71, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 72, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 73, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 74, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 75, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 76, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 77, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 78, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 79, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 80, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 81, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 82, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 83, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 84, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 85, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 86, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 87, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 88, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 89, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 90, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 91, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 92, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 93, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 94, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 95, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 96, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 97, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 98, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 99, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 100, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 101, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 102, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 103, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 104, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 105, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 106, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 107, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 108, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 109, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 110, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 111, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 112, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 113, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 114, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 115, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 116, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 117, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 118, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 119, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 120, + "color": "blue", + "congruent": 1, + "word": "blue" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/stroop-task/stimuli_2_1.ts b/src/app/pages/experiments/stroop-task/stimuli_2_1.ts new file mode 100644 index 00000000..ad10bc8f --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stimuli_2_1.ts @@ -0,0 +1,722 @@ +export const set = [ + { + "trial": 1, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 2, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 3, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 4, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 5, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 6, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 7, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 8, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 9, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 10, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 11, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 12, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 13, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 14, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 15, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 16, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 17, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 18, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 19, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 20, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 21, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 22, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 23, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 24, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 25, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 26, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 27, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 28, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 29, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 30, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 31, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 32, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 33, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 34, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 35, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 36, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 37, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 38, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 39, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 40, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 41, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 42, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 43, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 44, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 45, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 46, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 47, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 48, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 49, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 50, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 51, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 52, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 53, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 54, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 55, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 56, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 57, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 58, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 59, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 60, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 61, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 62, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 63, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 64, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 65, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 66, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 67, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 68, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 69, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 70, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 71, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 72, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 73, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 74, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 75, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 76, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 77, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 78, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 79, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 80, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 81, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 82, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 83, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 84, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 85, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 86, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 87, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 88, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 89, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 90, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 91, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 92, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 93, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 94, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 95, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 96, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 97, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 98, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 99, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 100, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 101, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 102, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 103, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 104, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 105, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 106, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 107, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 108, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 109, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 110, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 111, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 112, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 113, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 114, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 115, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 116, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 117, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 118, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 119, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 120, + "color": "blue", + "congruent": 1, + "word": "blue" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/stroop-task/stimuli_3_1.ts b/src/app/pages/experiments/stroop-task/stimuli_3_1.ts new file mode 100644 index 00000000..f403d41c --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stimuli_3_1.ts @@ -0,0 +1,722 @@ +export const set = [ + { + "trial": 1, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 2, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 3, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 4, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 5, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 6, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 7, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 8, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 9, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 10, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 11, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 12, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 13, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 14, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 15, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 16, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 17, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 18, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 19, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 20, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 21, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 22, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 23, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 24, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 25, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 26, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 27, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 28, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 29, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 30, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 31, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 32, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 33, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 34, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 35, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 36, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 37, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 38, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 39, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 40, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 41, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 42, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 43, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 44, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 45, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 46, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 47, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 48, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 49, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 50, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 51, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 52, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 53, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 54, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 55, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 56, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 57, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 58, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 59, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 60, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 61, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 62, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 63, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 64, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 65, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 66, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 67, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 68, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 69, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 70, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 71, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 72, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 73, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 74, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 75, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 76, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 77, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 78, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 79, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 80, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 81, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 82, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 83, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 84, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 85, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 86, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 87, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 88, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 89, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 90, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 91, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 92, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 93, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 94, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 95, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 96, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 97, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 98, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 99, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 100, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 101, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 102, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 103, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 104, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 105, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 106, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 107, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 108, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 109, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 110, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 111, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 112, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 113, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 114, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 115, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 116, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 117, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 118, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 119, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 120, + "color": "blue", + "congruent": 1, + "word": "blue" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/stroop-task/stimuli_4_1.ts b/src/app/pages/experiments/stroop-task/stimuli_4_1.ts new file mode 100644 index 00000000..96ca8bb6 --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stimuli_4_1.ts @@ -0,0 +1,722 @@ +export const set = [ + { + "trial": 1, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 2, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 3, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 4, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 5, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 6, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 7, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 8, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 9, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 10, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 11, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 12, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 13, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 14, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 15, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 16, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 17, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 18, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 19, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 20, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 21, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 22, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 23, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 24, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 25, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 26, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 27, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 28, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 29, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 30, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 31, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 32, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 33, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 34, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 35, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 36, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 37, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 38, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 39, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 40, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 41, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 42, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 43, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 44, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 45, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 46, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 47, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 48, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 49, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 50, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 51, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 52, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 53, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 54, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 55, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 56, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 57, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 58, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 59, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 60, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 61, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 62, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 63, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 64, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 65, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 66, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 67, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 68, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 69, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 70, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 71, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 72, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 73, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 74, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 75, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 76, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 77, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 78, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 79, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 80, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 81, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 82, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 83, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 84, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 85, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 86, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 87, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 88, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 89, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 90, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 91, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 92, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 93, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 94, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 95, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 96, + "color": "blue", + "congruent": 0, + "word": "red" + }, + { + "trial": 97, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 98, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 99, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 100, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 101, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 102, + "color": "red", + "congruent": 0, + "word": "green" + }, + { + "trial": 103, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 104, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 105, + "color": "red", + "congruent": 0, + "word": "blue" + }, + { + "trial": 106, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 107, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 108, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 109, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 110, + "color": "blue", + "congruent": 0, + "word": "green" + }, + { + "trial": 111, + "color": "green", + "congruent": 0, + "word": "blue" + }, + { + "trial": 112, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 113, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 114, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 115, + "color": "green", + "congruent": 0, + "word": "red" + }, + { + "trial": 116, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 117, + "color": "blue", + "congruent": 1, + "word": "blue" + }, + { + "trial": 118, + "color": "red", + "congruent": 1, + "word": "red" + }, + { + "trial": 119, + "color": "green", + "congruent": 1, + "word": "green" + }, + { + "trial": 120, + "color": "blue", + "congruent": 1, + "word": "blue" + } +] \ No newline at end of file diff --git a/src/app/pages/experiments/stroop-task/stroop-task.component.html b/src/app/pages/experiments/stroop-task/stroop-task.component.html new file mode 100644 index 00000000..67d75d48 --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stroop-task.component.html @@ -0,0 +1,355 @@ +
+ + +
+ +
+ + +
+ + +
+

Welcome to Stroop Task

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, you will be presented with different words for colors (eg. 'BLUE') printed in different + color font. +
+ +
+ It's your goal to respond to the color of the font that the word is printed in, not the word itself. +
+ +
+ 1 = 'RED' +
+ 2 = 'BLUE' +
+ 3 = 'GREEN' +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Good luck ! You will have very little time to respond, so be ready. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ {{text}} +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+
+ {{text}} +
+
+
+ +
+ add +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ Your earnings in this game is : {{totalScore}} cent(s) +
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + + +
+ +
+

It's break time

+
+ + +
+ + +
+ Take a short break +
+ +
+ +
+ Click 'RESUME' when you are ready +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/pages/experiments/stroop-task/stroop-task.component.scss b/src/app/pages/experiments/stroop-task/stroop-task.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/stroop-task/stroop-task.component.ts b/src/app/pages/experiments/stroop-task/stroop-task.component.ts new file mode 100644 index 00000000..5223ee6f --- /dev/null +++ b/src/app/pages/experiments/stroop-task/stroop-task.component.ts @@ -0,0 +1,349 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +declare function setFullScreen(): any; +import * as Set1 from './stimuli_1_1'; +import * as Set2 from './stimuli_2_1'; +import * as Set3 from './stimuli_3_1'; +import * as Set4 from './stimuli_4_1'; + +@Component({ + selector: 'app-stroop-task', + templateUrl: './stroop-task.component.html', + styleUrls: ['./stroop-task.component.scss'] +}) +export class StroopTaskComponent implements OnInit { + + // Default Experiment config + isScored: boolean | number = true; + showFeedbackAfterEveryTrial: boolean | number = false; + showScoreAfterEveryTrial: boolean | number = false; + numberOfBreaks: number = 0; + maxResponseTime: number = 2000; // In milliseconds + durationOfFeedback: number = 500; // In milliseconds + interTrialDelay: number = 1000; // In milliseconds + practiceTrials: number = 10; + actualTrials: number = 120; + + step: number = 1; + color: string = ''; + text: string = ''; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + actualAnswer: string, + userAnswer: string, + isCongruent: number, + responseTime: number, + isCorrect: number, + score: number, + set: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + set: number; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + + @HostListener('window:keypress', ['$event']) + onKeyPress(event: KeyboardEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (!!event.key) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + switch (event.key) { + case '1': this.data[this.data.length - 1].userAnswer = 'red'; break; + case '2': this.data[this.data.length - 1].userAnswer = 'blue'; break; + case '3': this.data[this.data.length - 1].userAnswer = 'green'; break; + default: this.data[this.data.length - 1].userAnswer = ''; break; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } + } catch (error) { + } + } + } + + + constructor( + private router: Router, + private dataService: DataService + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored; + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial; + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial; + this.numberOfBreaks = currentExperiment.numberOfBreaks; + this.maxResponseTime = currentExperiment.maxResponseTime; + this.durationOfFeedback = currentExperiment.durationOfFeedback; + this.interTrialDelay = currentExperiment.interTrialDelay; + this.practiceTrials = currentExperiment.practiceTrials; + this.actualTrials = currentExperiment.actualTrials; + this.set = Math.floor(Math.random() * 4) + 1; + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + + async startPractice() { + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + + } + + + + generateStimulus() { + switch (this.set) { + case 1: + this.color = Set1.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].color; + this.text = Set1.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].word; + break; + case 2: + this.color = Set2.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].color; + this.text = Set2.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].word; + break; + case 3: + this.color = Set3.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].color; + this.text = Set3.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].word; + break; + case 4: + this.color = Set4.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].color; + this.text = Set4.set[this.currentTrial - 1 + (this.isPractice ? 0 : 10)].word; + break; + } + + this.data.push({ + actualAnswer: this.color, + userAnswer: 'NA', + isCongruent: this.color === this.text ? 1 : 0, + responseTime: 0, + isCorrect: 0, + score: 0, + set: this.set + }); + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === 'NA') { + this.feedback = "Too slow" + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.color = ''; + this.text = ''; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/task-switching/matrix.ts b/src/app/pages/experiments/task-switching/matrix.ts new file mode 100644 index 00000000..785bca83 --- /dev/null +++ b/src/app/pages/experiments/task-switching/matrix.ts @@ -0,0 +1,13 @@ +export class Matrix { + colors: number[] = [ + 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1 + ]; + + colors2: number[] = [ + 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2 + ]; + + digits: number[] = [ + 4, 7, 6, 9, 6, 4, 1, 8, 7, 3, 2, 4, 7, 3, 4, 8, 2, 4, 1, 2, 6, 7, 2, 9, 3, 6, 3, 2, 9, 2, 1, 9, 1, 7, 8, 6, 1, 8, 7, 3, 9, 4, 9, 1, 7, 4, 2, 4, 7, 8, 7, 1, 2, 6, 1, 2, 9, 3, 7, 2, 9, 1, 2, 1, 3, 1, 2, 7, 8, 9, 8, 2, 9, 4, 1, 6, 7, 3, 9, 7, 6, 4, 8, 6, 4, 8, 7, 6, 4, 7, 9, 4, 6, 2, 8, 1, 7, 3, 8, 2, 8, 1, 6, 7, 4, 1, 6, 1, 3, 8, 7, 6, 2, 7, 4, 2, 8, 3, 2, 1, 3, 8, 9, 4, 8 + ]; +} \ No newline at end of file diff --git a/src/app/pages/experiments/task-switching/task-switching.component.html b/src/app/pages/experiments/task-switching/task-switching.component.html new file mode 100644 index 00000000..99d598bd --- /dev/null +++ b/src/app/pages/experiments/task-switching/task-switching.component.html @@ -0,0 +1,642 @@ +
+ + +
+ +
+ + +
+
+

+
+
+
+ Thank you for participating. +
+
+ You will be playing brain games. +
+
+ We will first go through the instructions for the games and then you will have an opportunity to + practice. +
+
+ Click 'NEXT' to proceed +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

Welcome to Number Game

+
+
+
+

+ Read the instructions carefully +

+
+
+ You will see a number on the screen. +
+
+ That number is either blue or yellow. +
+
+ The color is important: it tells you what you must identify + about that number. +
+
+ When the number is BLUE, you must indicate if the number is lesser or greater than 5. +
+
+ When the number is YELLOW, you must indicate if the number is odd or even. +
+
+ You will use the mouse to provide your answer. +
+
+ Click 'NEXT' to proceed +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

+
+
+
+

+
+
+ 3 +
+
+ If number is GREATER THAN 5: click the left mouse button +
+
+ If number is LESSER THAN 5: click the right mouse button +
+
+
+ 8 +
+
+ Click 'NEXT' to proceed +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

+
+
+
+ Remember, the color of the number tells you what you must identify about that number. +
+
+
+ 3 +
+
+ If number is GREATER THAN 5: click the left mouse button +
+
+ If number is LESSER THAN 5: click the right mouse button +
+
+
+ 8 +
+
+ Click 'NEXT' to proceed +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

Practice Round

+
+
+
+

Let's Practice

+
+
+
+ The game will launch in fullscreen +
+
+ Click 'START' when you are ready for the practice round +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{number}} +
+
+ +
+ +
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+ You got {{totalScore/10}} out of {{practiceTrials}} trials correct +
+ +
+ +
+ Click 'REPEAT' to practice again, or +
+ +
+ Click 'NEXT' when you are ready for the next stage. +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

Practice Round

+
+
+
+

Let's practice again

+
+
+
+ This time we won’t give you feedback after each answer. +
+
+
+ Do your best! +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

+
+
+
+ Remember, the color of the number tells you what you must identify about that number. +
+
+
+ 3 +
+
+ If number is GREATER THAN 5: click the left mouse button +
+
+ If number is LESSER THAN 5: click the right mouse button +
+
+
+ 8 +
+
+ Click 'START' to start the practice +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{number}} +
+
+ +
+ +
+ +
+ +
+
+ + + +
+ +
+ + + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+ You got {{totalScore/10}} out of {{practiceTrials}} trials correct +
+ +
+ +
+ Click 'REPEAT' to practice again, or +
+ +
+ Click 'NEXT' when you are ready for the next stage. +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+

Main Round

+
+
+
+

Great! Now you will play the real game.

+
+
+
+ The game will launch in fullscreen +
+
+ Click 'START' when you are ready for the actual round. +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+
+ {{number}} +
+
+ +
+ +
+ +
+ +
+
+ + + +
+ +
+ + + +
+ +
+

Main Round Is Now Complete

+
+ + +
+ +
+ You got {{totalScore/10}} out of {{actualTrials}} trials correct +
+ +
+ +
+ Click 'NEXT' when you are ready for the next stage. +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/experiments/task-switching/task-switching.component.scss b/src/app/pages/experiments/task-switching/task-switching.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/pages/experiments/task-switching/task-switching.component.ts b/src/app/pages/experiments/task-switching/task-switching.component.ts new file mode 100644 index 00000000..1521f63a --- /dev/null +++ b/src/app/pages/experiments/task-switching/task-switching.component.ts @@ -0,0 +1,374 @@ +import { Component, OnInit, HostListener } from '@angular/core'; +import { Router } from '@angular/router'; +import { Matrix } from './matrix'; +declare function setFullScreen(): any; +@Component({ + selector: 'app-task-switching', + templateUrl: './task-switching.component.html', + styleUrls: ['./task-switching.component.scss'] +}) +export class TaskSwitchingComponent implements OnInit { + + isScored: boolean = false; + showFeedbackAfterEveryTrial: boolean = false; + showScoreAfterEveryTrial: boolean = false; + numberOfBreaks: number = 0; + maxResponseTime: number = 2500; + durationOfFeedback: number = 500; + interTrialDelay: number = 1000; + practiceTrials: number = 20; + actualTrials: number = 125; + + step: number = 1; + color: string = 'transparent'; + number: number = 0; + feedback: string = ''; + scoreForSpecificTrial: number = 0; + totalScore: number = 0; + isPractice: boolean = false; + isStimulus: boolean = false; + isBreak: boolean = false; + fRepeat = true; + currentTrial: number = 0; + isResponseAllowed: boolean = false; + data: { + color: string, + digit: number, + actualAnswer: string, + userAnswer: string, + responseTime: number, + isCorrect: number, + score: number + }[] = []; + timer: { + started: number, + ended: number + } = { + started: 0, + ended: 0 + }; + showFixation: boolean = false; + sTimeout: any; + feedbackShown: boolean = false; + matrix = new Matrix(); + + @HostListener('document:click', ['$event']) + onKeyPress(event: MouseEvent) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (this.data[this.data.length - 1].color === 'blue') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'LESSER'; + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'ODD'; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } catch (error) { + } + } + } + + + + constructor( + private router: Router + ) { } + + + + ngOnInit() { + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep(steps = 1) { + if (steps > 1) { + this.fRepeat = false; + } + this.step -= steps; + } + + + + proceedtoNextStep(steps = 1) { + this.step += steps; + } + + processClickEvent(event: any) { + if (this.isResponseAllowed) { + this.isResponseAllowed = false; + try { + if (this.data[this.data.length - 1].color === 'blue') { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'GREATER'; + } else { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + this.data[this.data.length - 1].userAnswer = 'EVEN'; + } + try { + clearTimeout(this.sTimeout); + this.showFeedback(); + } catch (error) { + } + } catch (error) { + } + } + event.preventDefault(); + } + + + + async startPractice(trials = 0) { + if (trials !== 0) { + this.practiceTrials = trials; + } + this.startGameInFullScreen(); + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = true; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async startActualGame() { + this.resetData(); + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.isPractice = false; + this.showFeedbackAfterEveryTrial = false; + this.showScoreAfterEveryTrial = false; + this.currentTrial = 0; + this.showStimulus(); + } + + + + async showStimulus() { + + this.reset(); + this.showFixation = true; + await this.wait(500); + this.showFixation = false; + await this.wait(200); + + this.currentTrial += 1; + this.generateStimulus(); + this.isStimulus = true; + this.isResponseAllowed = true; + + this.timer.started = new Date().getTime(); + this.timer.ended = 0; + + console.log(this.isPractice ? `Practice trial: ${this.currentTrial}` : `Actual trial: ${this.currentTrial}`); + + // This is the delay between showing the stimulus and showing the feedback + this.sTimeout = setTimeout(() => { + if (!this.feedbackShown) { + this.showFeedback(); + } + }, this.maxResponseTime); + } + + + + generateStimulus() { + const rand = this.matrix.colors[this.currentTrial - 1]; + + let color = 'blue'; + if (rand === 1) { + color = 'blue'; + } else { + color = 'yellow'; + } + + const digit = this.matrix.digits[this.currentTrial - 1]; + + let answer = ''; + + if (color === 'yellow') { + if (digit % 2 === 0) { + answer = 'EVEN'; + } else { + answer = 'ODD'; + } + } else { + if (digit > 5) { + answer = 'GREATER'; + } else { + answer = 'LESSER'; + } + } + + this.color = color; + this.number = digit; + + this.data.push({ + color: color, + digit: digit, + actualAnswer: answer, + userAnswer: '', + responseTime: 0, + isCorrect: 0, + score: 0 + }); + + } + + + + async showFeedback() { + this.feedbackShown = true; + this.isStimulus = false; + this.isResponseAllowed = false; + + if (this.data[this.data.length - 1].responseTime === 0) { + this.timer.ended = new Date().getTime(); + this.data[this.data.length - 1].responseTime = Number(((this.timer.ended - this.timer.started) / 1000).toFixed(2)); + } + + if (this.data[this.data.length - 1].actualAnswer === this.data[this.data.length - 1].userAnswer) { + this.feedback = "Correct"; + this.data[this.data.length - 1].isCorrect = 1; + this.data[this.data.length - 1].score = 10; + this.scoreForSpecificTrial = 10; + this.totalScore += 10; + } else { + if (this.data[this.data.length - 1].userAnswer === '') { + this.feedback = "Too slow"; + } else { + this.feedback = "Incorrect"; + } + this.data[this.data.length - 1].isCorrect = 0; + this.data[this.data.length - 1].score = 0; + this.scoreForSpecificTrial = 0; + } + + if (this.showFeedbackAfterEveryTrial || this.isPractice) { + await this.wait(this.durationOfFeedback); + } + this.decideToContinue(); + } + + + + async decideToContinue() { + if (this.isPractice) { + if (this.currentTrial < this.practiceTrials) { + this.continueGame(); + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + } else { + if (this.currentTrial < this.actualTrials) { + if (this.numberOfBreaks === 0) { + this.continueGame(); + } else { + let breakAtTrailIndices = []; + let setSize = this.actualTrials / (this.numberOfBreaks + 1); + for (let i = 1; i < this.numberOfBreaks + 1; i++) { + breakAtTrailIndices.push(setSize * i); + } + if (breakAtTrailIndices.includes(this.currentTrial)) { + this.isBreak = true; + } else { + this.isBreak = false; + this.continueGame(); + } + } + } else { + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + console.log(this.data); + } + } + } + + + + resume() { + this.reset(); + this.isBreak = false; + this.continueGame(); + } + + + + async continueGame() { + await this.wait(this.interTrialDelay); + this.showStimulus(); + } + + + + uploadResults() { + } + + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + reset() { + this.number = 0; + this.color = 'transparent'; + this.feedback = ''; + this.feedbackShown = false; + this.scoreForSpecificTrial = 0; + } + + + + resetData() { + this.data = []; + this.totalScore = 0; + } + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/experiments/trail-making/trail-making.component.html b/src/app/pages/experiments/trail-making/trail-making.component.html new file mode 100644 index 00000000..1cfc44b1 --- /dev/null +++ b/src/app/pages/experiments/trail-making/trail-making.component.html @@ -0,0 +1,976 @@ +
+ +
+ +
+ + +
+ + +
+

Welcome to the Trail Making Task - Part 1

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, you will be shown numbered circles on the screen that are randomly arranged. +
+ +
+ It's your goal to click on the numbered circles in an increasing order. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Try clicking numbers from 1 to 2 and so forth. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + +
+
+ + +
+ + + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ You have 4 minutes to finish this task. +
+ +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +
+ + +
+ + +
+

Welcome to the Trail Making Task - Part 2

+
+ + +
+ +
+

+ Read the instructions carefully +

+
+ +
+ In this task, you will be shown circles with numbers and letters on the screen that are randomly + arranged. +
+ +
+ You will be clicking both numbers and letters on the screen in increasing, alphabetical order. +
+ +
+ Click 'NEXT' to proceed +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+

Practice Round

+
+ + +
+ +
+

Let's Practice

+
+ +
+ Try clicking in the following pattern: 1-A-2-B-3-C and so on. +
+ +
+ +
+ The game will launch in fullscreen +
+ +
+ Click 'START' when you are ready for the practice round +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + +
+
+ + +
+ + + +
+ +
+

Practice Round Is Now Complete

+
+ + +
+ +
+

You will now play the actual game

+
+ +
+ You will earn 10 cents for every right answer +
+ +
+ Good luck ! +
+ +
+ You have 4 minutes to finish this task. +
+ +
+ +
+ Click 'START' when you are ready for the actual game +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + +
+
+ + +
+ + +
+ +
+

Game has finished

+
+ + +
+ +
+

Congratulations ! You have finished the game successfully

+
+ +
+ +
+ Thank you for your participation +
+ +
+ Click 'CONTINUE' +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
\ No newline at end of file diff --git a/src/app/pages/experiments/trail-making/trail-making.component.scss b/src/app/pages/experiments/trail-making/trail-making.component.scss new file mode 100644 index 00000000..8dc4912f --- /dev/null +++ b/src/app/pages/experiments/trail-making/trail-making.component.scss @@ -0,0 +1,7 @@ +td { + padding: 25px; +} + +button.fab { + font-size: 20px; +} \ No newline at end of file diff --git a/src/app/pages/experiments/trail-making/trail-making.component.ts b/src/app/pages/experiments/trail-making/trail-making.component.ts new file mode 100644 index 00000000..b669d32e --- /dev/null +++ b/src/app/pages/experiments/trail-making/trail-making.component.ts @@ -0,0 +1,153 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { DataService } from 'src/app/services/data.service'; +import { MatSnackBar } from '@angular/material/snack-bar'; +declare function setFullScreen(): any; + +@Component({ + selector: 'app-trail-making', + templateUrl: './trail-making.component.html', + styleUrls: ['./trail-making.component.scss'] +}) +export class TrailMakingComponent implements OnInit { + + + step: number = 1; + isScored: number | boolean; + showFeedbackAfterEveryTrial: number | boolean; + showScoreAfterEveryTrial: number | boolean; + numberOfBreaks: number; + maxResponseTime: number; + durationOfFeedback: number; + interTrialDelay: number; + practiceTrials: number; + actualTrials: number; + sTimeout; + clicked: number[] = []; + correct: number[] = []; + sTimeout2; + + + constructor( + private router: Router, + private dataService: DataService, + private snackbar: MatSnackBar + ) { } + + + + ngOnInit() { + let route_split = this.router.url.split('/'); + let routePath = route_split[route_split.length - 1]; + let currentExperiment = this.dataService.getExperimentByRoute(routePath); + this.isScored = currentExperiment.isScored; + this.showFeedbackAfterEveryTrial = currentExperiment.showFeedbackAfterEveryTrial; + this.showScoreAfterEveryTrial = currentExperiment.showScoreAfterEveryTrial; + this.numberOfBreaks = currentExperiment.numberOfBreaks; + this.maxResponseTime = currentExperiment.maxResponseTime; + this.durationOfFeedback = currentExperiment.durationOfFeedback; + this.interTrialDelay = currentExperiment.interTrialDelay; + this.practiceTrials = currentExperiment.practiceTrials; + this.actualTrials = currentExperiment.actualTrials; + } + + + + processConsent(consent: Boolean) { + if (consent) { + this.proceedtoNextStep(); + } else { + this.router.navigate(['/dashboard']); + } + } + + + + proceedtoPreviousStep() { + this.step -= 1; + } + + + + proceedtoNextStep() { + this.step += 1; + } + + getColor(number: number) { + return this.clicked.includes(number) ? (this.clicked[number - 1] === number ? 'green' : 'red') : 'whitesmoke'; + } + + registerClick(number: number) { + if (!this.clicked.includes(number)) { + this.clicked.push(number); + if (this.clicked[this.clicked.length - 1] !== this.correct[this.clicked.length - 1]) { + let audio = new Audio('/assets/sounds/wrong.mp3'); + audio.play(); + this.sTimeout = setTimeout(() => { + this.clicked.pop(); + }, 500); + } else { + let audio = new Audio('/assets/sounds/correct.mp3'); + audio.play(); + } + try { + clearTimeout(this.sTimeout2); + } catch (error) { + + } + this.sTimeout2 = setTimeout(() => { + if (this.clicked.length === this.correct.length) { + this.clicked = []; + this.proceedtoNextStep(); + } + }, 1500); + } + } + + async startPractice() { + this.clicked = []; + this.correct = [1, 2, 3, 4, 5, 6, 7, 8]; + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + } + + async startActual() { + this.clicked = []; + this.correct = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]; + this.proceedtoNextStep(); + await this.wait(2000); + this.proceedtoNextStep(); + this.sTimeout = setTimeout(() => { + this.proceedtoNextStep(); + this.snackbar.open('Timeout', '', { duration: 2000 }); + }, 240000); + } + + + uploadResults() { + } + + + continueAhead() { + this.router.navigate(['/dashboard']); + } + + + + + startGameInFullScreen() { + setFullScreen(); + } + + + + wait(time: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); + } + +} diff --git a/src/app/pages/login/login.component.html b/src/app/pages/login/login.component.html new file mode 100644 index 00000000..a84c9441 --- /dev/null +++ b/src/app/pages/login/login.component.html @@ -0,0 +1,24 @@ +
+ +
\ No newline at end of file diff --git a/src/app/pages/login/login.component.scss b/src/app/pages/login/login.component.scss new file mode 100644 index 00000000..218ea7bc --- /dev/null +++ b/src/app/pages/login/login.component.scss @@ -0,0 +1,9 @@ +.login{ + height: calc(100vh - 60px); +} +.card-body{ + padding-top: 0px; +} +.card{ + border-color: #cecece; +} \ No newline at end of file diff --git a/src/app/pages/login/login.component.ts b/src/app/pages/login/login.component.ts new file mode 100644 index 00000000..38587374 --- /dev/null +++ b/src/app/pages/login/login.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { LoginCredentials } from 'src/app/models/LoginCredentials'; +import { AuthService } from 'src/app/services/auth.service'; +import { Subscription } from 'rxjs'; +import { HttpErrorResponse } from '@angular/common/http'; +import { LoginResponse } from 'src/app/models/LoginResponse'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'] +}) +export class LoginComponent implements OnInit, OnDestroy { + + + + model: LoginCredentials = new LoginCredentials(); + + + + loginSubscription: Subscription = new Subscription(); + + + + constructor( + private authService: AuthService, + private router: Router + ) { } + + ngOnInit() { + } + + + proceed() { + this.loginSubscription = this.authService.login(this.model).subscribe((response: LoginResponse) => { + localStorage.setItem('token', response.token); + this.router.navigate(['/dashboard']); + }, (error: HttpErrorResponse) => { + console.error(error); + }); + } + + ngOnDestroy() { + this.loginSubscription.unsubscribe(); + } + +} diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts new file mode 100644 index 00000000..e90bea87 --- /dev/null +++ b/src/app/services/auth.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { LoginCredentials } from '../models/LoginCredentials'; +import { HttpClient } from '@angular/common/http'; +import { environment } from 'src/environments/environment'; +import { Observable } from 'rxjs'; +import { LoginResponse } from '../models/LoginResponse'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + + constructor(private http: HttpClient) { } + + login(model: LoginCredentials): Observable { + return this.http.post(environment.apiBaseURL + '/login', model); + } + +} diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts new file mode 100644 index 00000000..936f22f0 --- /dev/null +++ b/src/app/services/data.service.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { environment } from 'src/environments/environment'; +import { Observable } from 'rxjs'; +import { Experiment } from '../models/Experiment'; + +@Injectable({ + providedIn: 'root' +}) +export class DataService { + + private experiments = []; + + constructor( + private http: HttpClient + ) { } + + setExperiments(experiments: Experiment[]): void { + this.experiments = experiments; + } + + getExperimentByRoute(route: string): Experiment { + let exp = null; + this.experiments.forEach((experiment: Experiment) => { + if (experiment.route === route) { + exp = experiment; + } + }); + return exp; + } + + getExperiments(): Observable { + return this.http.get(environment.apiBaseURL + '/experiments'); + } +} diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/assets/abst01a.png b/src/assets/abst01a.png new file mode 100644 index 00000000..d2a2e783 Binary files /dev/null and b/src/assets/abst01a.png differ diff --git a/src/assets/abst01b.png b/src/assets/abst01b.png new file mode 100644 index 00000000..f8cea363 Binary files /dev/null and b/src/assets/abst01b.png differ diff --git a/src/assets/eye.png b/src/assets/eye.png new file mode 100644 index 00000000..b7f93e5e Binary files /dev/null and b/src/assets/eye.png differ diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 00000000..7bf14cd4 Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/long.png b/src/assets/long.png new file mode 100644 index 00000000..b8380d0a Binary files /dev/null and b/src/assets/long.png differ diff --git a/src/assets/no.png b/src/assets/no.png new file mode 100644 index 00000000..c45ec1de Binary files /dev/null and b/src/assets/no.png differ diff --git a/src/assets/short.png b/src/assets/short.png new file mode 100644 index 00000000..a39a229a Binary files /dev/null and b/src/assets/short.png differ diff --git a/src/assets/sounds/correct.mp3 b/src/assets/sounds/correct.mp3 new file mode 100644 index 00000000..9dc80446 Binary files /dev/null and b/src/assets/sounds/correct.mp3 differ diff --git a/src/assets/sounds/wrong.mp3 b/src/assets/sounds/wrong.mp3 new file mode 100644 index 00000000..96d8f968 Binary files /dev/null and b/src/assets/sounds/wrong.mp3 differ diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts new file mode 100644 index 00000000..83fd6498 --- /dev/null +++ b/src/environments/environment.prod.ts @@ -0,0 +1,4 @@ +export const environment = { + production: true, + apiBaseURL: 'https://api-sharplab.duckdns.org/api' +}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts new file mode 100644 index 00000000..6ebc2c3b --- /dev/null +++ b/src/environments/environment.ts @@ -0,0 +1,4 @@ +export const environment = { + production: false, + apiBaseURL: 'https://api-sharplab.duckdns.org/api' +}; diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 00000000..64b772a7 Binary files /dev/null and b/src/favicon.ico differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..83c1171c --- /dev/null +++ b/src/index.html @@ -0,0 +1,59 @@ + + + + + + Axon + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 00000000..e76caeea --- /dev/null +++ b/src/main.ts @@ -0,0 +1,13 @@ + +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/src/polyfills.ts b/src/polyfills.ts new file mode 100644 index 00000000..aa665d6b --- /dev/null +++ b/src/polyfills.ts @@ -0,0 +1,63 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/src/styles.scss b/src/styles.scss new file mode 100644 index 00000000..e800916f --- /dev/null +++ b/src/styles.scss @@ -0,0 +1,122 @@ +html, body { height: 100%; } +body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; background-color: white; } + +button{ + outline: none !important; +} + +.wrapper{ + + height: 100%; + padding: 25px; + font-family: 'Roboto Mono', monospace; + + .full-box{ + width: 100%; + height: 100%; + border: solid thin #cccccc; + border-radius: 5px; + } + + .scrollable{ + max-height: 100%; + overflow-y: auto; + background: #eeeeee; + } + + .bottom-button-bar{ + margin-top: 50px; + margin-bottom: 50px; + } + + p{ + text-align: justify; + } + + .uppercase{ + text-transform: uppercase; + } + + .title{ + text-decoration: underline; + padding: 25px; + } + .statement { + padding: 15px; + font-size: 20px; + } + + .statement-final { + padding: 30px; + font-size: 20px; + font-weight: bold; + } + + .square { + height: 200px; + width: 200px; + } + + .feedback { + font-size: 30px; + text-transform: uppercase; + } + + .rect{ + height: 50px; + width: 50px; + border-radius: 0%; + margin: 5px; + text-align: left; + border: solid thin #000; + } + +.circle{ + height: 50px; + width: 50px; + border-radius: 50%; + margin: 5px; + text-align: left; + border: solid thin #000; + } + +.teal{ + background-color: green; +} +.red{ + background-color: red; +} +.orange{ + background-color: orange; +} +.purple{ + background-color: purple; +} +.pink{ + background-color: pink; +} +.brown{ + background-color: brown; +} +.grey{ + background-color: grey; +} +.blue{ + background-color: blue; +} + + +.light{ + font-weight: lighter; +} + +.big{ + height: 75px; + width: 75px; +} + +} + +*:fullscreen, *:-webkit-full-screen, *:-moz-full-screen { + background-color: rgba(255,255,255,0); +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 00000000..df4d05e1 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..e5265a4b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + }, + "angularCompilerOptions": { + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true + } +} \ No newline at end of file