Index

shared/common/modules/apm/constants.ts

APM_INSTANCE
Default value : Symbol('APM_INSTANCE')
APM_TRANSACTION_DECORATOR
Default value : Symbol('APM_TRANSACTION_DECORATOR')

shared/common/catch-and-log-error.decorator.ts

ApplyDecoratorToAll
Default value : ( decorator: MethodDecorator, opts: ApplyToAllOpts, ) => { return (target: any) => { const descriptors = Object.getOwnPropertyDescriptors(target.prototype); for (const [propName, descriptor] of Object.entries(descriptors)) { const isMethod = descriptor.value instanceof Function && propName != 'constructor'; if (!isMethod) continue; if (opts?.exclude?.includes(propName)) continue; const originalMethod = descriptor.value; // apply decorator decorator(target, propName, descriptor) // copy metadata if (originalMethod != descriptor.value) { const metadataKeys = Reflect.getMetadataKeys(originalMethod); metadataKeys.map((key) => { const value = Reflect.getMetadata(key, originalMethod); Reflect.defineMetadata(key, value, descriptor.value); }); } // Do not define property if sync function, or will be returned as promise if (opts?.syncFunc?.includes(propName)) continue; Object.defineProperty(target.prototype, propName, descriptor); } }; }

Decorator to apply decorator to all methods in class

shared/constants/app.ts

CONSTANTS
Type : object
Default value : { /** tbl game join code length */ LIVE_GAME_JOIN_CODE_LENGTH: 6, /** spl game join code length */ SELF_PACED_LIVE_GAME_JOIN_CODE_LENGTH: 5, /** sp game join code length */ SELF_PACED_GAME_JOIN_CODE_LENGTH: 8, /** class score multiplier */ CLASS_SCORE_MULTIPLIER: 15, /** tbl game permanent code length */ LIVE_GAME_PERMANENT_CODE_LENGTH: 27, /** spl game permanent code length */ SELF_PACED_LIVE_PERMANENT_CODE_LENGTH: 28, /** sp game permanent code length */ SELF_PACED_GAME_PERMANENT_CODE_LENGTH: 29, /** max attempts to search uniqu codes */ SEARCH_UNIQUE_MAX_ATTEMPTS: 30, /** Math Runner game code length */ MATH_RUNNER_GAME_CODE_LENGTH: 4, /** Math Runner game lives */ MATH_RUNNER_LIVES: 6, }

common app constants

EMAIL_COLLATION_SETTINGS
Type : object
Default value : { locale: 'en', strength: 2 }

email settings

shared/common/decorators.ts

CurrentUser
Default value : createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.user; }, )

shared/common/modules/apm/decorators.ts

ElasticApmTransaction
Default value : (name: string) => { const data: TransactionDecoratorData = {name}; return SetMetadata(APM_TRANSACTION_DECORATOR, {name}) }

tbl/src/game-tbl/game-tbl.service.ts

EMPTY_GAME_TTL
Default value : 20 * 60

shared/utils/questions.ts

FALLBACK_XP_WEIGHT
Type : number
Default value : 0.2

default value for question weight calculation

getAnswerWeight
Default value : (questionBody: any): number => { let weight = FALLBACK_XP_WEIGHT; const { answer, correct, nr1 } = questionBody; if (!correct) { return 0; } switch (questionBody.type) { case 'TYPE_ADDITION': case 'TYPE_MULTIPLICATION': let maxSum = answer; let isNegative = false; if (maxSum < 0) { // For negative answers, convert it back to positive, // to get the weight. maxSum = maxSum * -1; isNegative = true; } for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (maxSum > key) { // @ts-ignore weight = isNegative ? value * NEGATIVE_MULTIPLIER : value; } } break; case 'TYPE_SUBTRACTION': case 'TYPE_DIVIDING': for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (nr1 > key) { // @ts-ignore weight = answer < 0 ? value * NEGATIVE_MULTIPLIER : value; } } break; case 'TYPE_CONVERSION': const questionUnits = QuestionWeightMap[questionBody.type].find( (units) => { const { unit1, unit2 } = units; const { convertFromUnit, convertToUnit } = questionBody.data; if ( (unit1 === convertFromUnit || unit1 === convertToUnit) && (unit2 === convertFromUnit || unit2 === convertToUnit) ) { return true; } return false; }, ); if (questionUnits) { weight = questionUnits.weight; } break; case 'TYPE_PERCENTAGE': const { type } = questionBody.data; let questionPercentage; for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (key === type) { questionPercentage = value; } } const compareByAnswer = type === 'relation' || type === 'comparison'; const pct = compareByAnswer ? answer : nr1; if (questionPercentage) { weight = questionPercentage[pct]; } break; } return weight / 4; }

util function getAnswerWeight - calculate answer xp depending on question conditions

NEGATIVE_MULTIPLIER
Type : number
Default value : 2

negative multiplier for question weight calculation

QuestionWeightMap
Type : object
Default value : { TYPE_ADDITION: { 0: 0.2, 10: 0.4, 20: 1.5, 100: 2.2, }, TYPE_SUBTRACTION: { 0: 0.3, 10: 0.5, 20: 1.7, 100: 2.4, }, TYPE_MULTIPLICATION: { 0: 0.3, 20: 1, 150: 2, }, TYPE_DIVIDING: { 0: 0.4, 20: 1.3, 150: 2, }, TYPE_CONVERSION: [ { unit1: 'km', unit2: 'm', weight: 0.4, }, { unit1: 'm', unit2: 'cm', weight: 0.4, }, { unit1: 'm', unit2: 'dm', weight: 0.4, }, { unit1: 'm', unit2: 'mm', weight: 0.4, }, { unit1: 'dm', unit2: 'cm', weight: 0.4, }, { unit1: 'dm', unit2: 'mm', weight: 0.4, }, { unit1: 'cm', unit2: 'mm', weight: 0.4, }, { unit1: 'ft', unit2: 'in', weight: 0.5, }, { unit1: 'yd', unit2: 'ft', weight: 0.5, }, { unit1: 'm^2', unit2: 'dm^2', weight: 0.5, }, { unit1: 'm^2', unit2: 'cm^2', weight: 0.5, }, { unit1: 'dm^2', unit2: 'cm^2', weight: 0.5, }, { unit1: 'cm^2', unit2: 'mm^2', weight: 0.5, }, { unit1: 'm^2', unit2: 'ha', weight: 0.5, }, { unit1: 'km^2', unit2: 'ha', weight: 0.5, }, { unit1: 'm^2', unit2: 'a', weight: 0.5, }, { unit1: 'm^3', unit2: 'dm^3', weight: 0.6, }, { unit1: 'dm^3', unit2: 'cm^3', weight: 0.6, }, { unit1: 'cm^3', unit2: 'mm^3', weight: 0.6, }, { unit1: 'dm^3', unit2: 'l', weight: 0.6, }, { unit1: 'l', unit2: 'ml', weight: 0.6, }, { unit1: 'gal', unit2: 'qt', weight: 0.8, }, { unit1: 'pt', unit2: 'qt', weight: 0.8, }, { unit1: 'c', unit2: 'pt', weight: 0.8, }, { unit1: 'floz', unit2: 'c', weight: 0.8, }, { unit1: 'c', unit2: 'qt', weight: 0.8, }, { unit1: 'c', unit2: 'gal', weight: 0.8, }, { unit1: 'gal', unit2: 'pt', weight: 0.8, }, { unit1: 't', unit2: 'kg', weight: 0.4, }, { unit1: 'kg', unit2: 'g', weight: 0.4, }, { unit1: 'g', unit2: 'mg', weight: 0.4, }, { unit1: 't', unit2: 'ts', weight: 0.4, }, { unit1: 'ts', unit2: 'kg', weight: 0.4, }, { unit1: 'lb', unit2: 'oz', weight: 0.4, }, ], TYPE_PERCENTAGE: { share: { 1: 0.5, 10: 0.5, 20: 1, 25: 1, 50: 1, 2: 1.5, 5: 1.5, 75: 1.5, 150: 1.5, }, whole: { 1: 0.6, 10: 0.6, 20: 1, 25: 1, 50: 1, 2: 1.5, 5: 1.5, 75: 1.5, 150: 1.5, }, relation: { 1: 0.8, 10: 0.8, 50: 1, 20: 1.5, 25: 1.5, 200: 1.5, }, comparison: { 1: 1.5, 10: 1.5, 50: 1.5, 25: 2, }, }, }

Initial static table of questions weights by types Weights are also divided by 4 in getAnswerWeight().

shared/utils/app.ts

gameModeByCode
Default value : (code: string): string => { if ( code.length === CONSTANTS.LIVE_GAME_JOIN_CODE_LENGTH || code.length === CONSTANTS.LIVE_GAME_PERMANENT_CODE_LENGTH ) return 'live'; if ( code.length === CONSTANTS.SELF_PACED_GAME_JOIN_CODE_LENGTH || code.length === CONSTANTS.SELF_PACED_GAME_PERMANENT_CODE_LENGTH ) return 'sp'; if ( code.length === CONSTANTS.SELF_PACED_LIVE_GAME_JOIN_CODE_LENGTH || code.length === CONSTANTS.SELF_PACED_LIVE_PERMANENT_CODE_LENGTH ) return 'splive'; return 'unknown'; }

util function to get game type by code length

getAnswerWeight
Default value : (questionBody: any): number => { let weight = FALLBACK_XP_WEIGHT; const { answer, correct, nr1 } = questionBody; if (!correct) { return 0; } switch (questionBody.type) { case 'TYPE_ADDITION': case 'TYPE_MULTIPLICATION': let maxSum = answer; let isNegative = false; if (maxSum < 0) { // For negative answers, convert it back to positive, // to get the weight. maxSum = maxSum * -1; isNegative = true; } for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (maxSum > key) { // @ts-ignore weight = isNegative ? value * NEGATIVE_MULTIPLIER : value; } } break; case 'TYPE_SUBTRACTION': case 'TYPE_DIVIDING': for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (nr1 > key) { // @ts-ignore weight = answer < 0 ? value * NEGATIVE_MULTIPLIER : value; } } break; case 'TYPE_CONVERSION': const questionUnits = QuestionWeightMap[questionBody.type].find( (units) => { const { unit1, unit2 } = units; const { convertFromUnit, convertToUnit } = questionBody.data; if ( (unit1 === convertFromUnit || unit1 === convertToUnit) && (unit2 === convertFromUnit || unit2 === convertToUnit) ) { return true; } return false; }, ); if (questionUnits) { weight = questionUnits.weight; } break; case 'TYPE_PERCENTAGE': const { type } = questionBody.data; let questionPercentage; for (const [key, value] of Object.entries( QuestionWeightMap[questionBody.type], )) { if (key === type) { questionPercentage = value; } } const compareByAnswer = type === 'relation' || type === 'comparison'; const pct = compareByAnswer ? answer : nr1; if (questionPercentage) { weight = questionPercentage[pct]; } break; } return weight / 4; }

util function getAnswerWeight - calculate answer xp depending on question conditions

shared/common/modules/apm/apm.util.ts

getInstance
Default value : (): APM.Agent => { if (!instance) { throw new Error('APM Agent is not initialized (run initializeAPMAgent) '); } return instance; }
initializeAPMAgent
Default value : (config?: APM.AgentConfigOptions): void => { if (instance) return; instance = config ? APM.start(config) : APM.start(); }
instance
Type : APM.Agent | undefined

shared/common/aws-service.ts

isCronRunningEnvironment
Default value : (): boolean => { if (!!process.env.WEBSOCKET_NO_REDIS) return true return process.env.RUN_CRON !== 'no'; }

Method to check if environment configured to run cron tasks (env.RUN_CRON !== 'no')

shared/constants/game.ts

LIVE_GAME_EMPTY_PLAYER_RESULT
Type : ReadonlyLiveGameEmptyPlayerResult
Default value : { score: 0, correctAnswers: 0, wrongAnswers: 0, rounds: [], }

empty player stats const

tbl/src/app.ts

module
Type : any

module declaration for webpack hot reload (for dev)

shared/common/modules/apm/apm.module.ts

providers
Type : Provider[]
Default value : [ ApmService, { provide: APM_INSTANCE, useFactory: () => { return getInstance(); }, }, ApmService, ElasticAPMInterceptor, ]

shared/common/socket-redis-io-adapter.ts

redisAdapter
Type : null
Default value : null
Default value : process.env

results matching ""

    No results matching ""