@pie-element/ebsr 13.1.2-next.5 → 13.2.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [13.2.0-next.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr@13.1.2-next.6...@pie-element/ebsr@13.2.0-next.0) (2026-03-18)
7
+
8
+ ### Features
9
+
10
+ - **ebsr:** add trace log for scoring in outcome function PD-5456 ([c83e1c2](https://github.com/pie-framework/pie-elements/commit/c83e1c29c8a0e7a03e3479cd00e9321b1e3f9edc))
11
+
12
+ ## [13.1.2-next.6](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr@13.1.2-next.5...@pie-element/ebsr@13.1.2-next.6) (2026-03-12)
13
+
14
+ ### Bug Fixes
15
+
16
+ - bump libs, update mathquill, switch interface PD-5791 ([686a7c0](https://github.com/pie-framework/pie-elements/commit/686a7c0d41ff82f5ddad7cecd93cc0c18324a81b))
17
+
6
18
  ## [13.1.2-next.5](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr@13.1.2-next.4...@pie-element/ebsr@13.1.2-next.5) (2026-03-09)
7
19
 
8
20
  **Note:** Version bump only for package @pie-element/ebsr
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [12.1.2-next.7](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-configure@12.1.2-next.6...@pie-element/ebsr-configure@12.1.2-next.7) (2026-03-18)
7
+
8
+ **Note:** Version bump only for package @pie-element/ebsr-configure
9
+
10
+ ## [12.1.2-next.6](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-configure@12.1.2-next.5...@pie-element/ebsr-configure@12.1.2-next.6) (2026-03-12)
11
+
12
+ ### Bug Fixes
13
+
14
+ - bump libs, update mathquill, switch interface PD-5791 ([686a7c0](https://github.com/pie-framework/pie-elements/commit/686a7c0d41ff82f5ddad7cecd93cc0c18324a81b))
15
+
6
16
  ## [12.1.2-next.5](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-configure@12.1.2-next.4...@pie-element/ebsr-configure@12.1.2-next.5) (2026-03-09)
7
17
 
8
18
  **Note:** Version bump only for package @pie-element/ebsr-configure
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pie-element/ebsr-configure",
3
3
  "private": true,
4
- "version": "12.1.2-next.5",
4
+ "version": "12.1.2-next.7",
5
5
  "description": "",
6
6
  "main": "lib/index.js",
7
7
  "module": "src/index.js",
@@ -11,9 +11,9 @@
11
11
  "@emotion/style": "^0.8.0",
12
12
  "@mui/icons-material": "^7.3.4",
13
13
  "@mui/material": "^7.3.4",
14
- "@pie-element/multiple-choice": "^12.1.2-next.5",
14
+ "@pie-element/multiple-choice": "^12.2.0-next.0",
15
15
  "@pie-framework/pie-configure-events": "^1.2.0",
16
- "@pie-lib/config-ui": "12.2.0-next.13",
16
+ "@pie-lib/config-ui": "12.2.0-next.17",
17
17
  "lodash-es": "^4.17.23",
18
18
  "prop-types": "^15.8.1",
19
19
  "react": "18.3.1",
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [10.2.0-next.0](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@10.1.1-next.1...@pie-element/ebsr-controller@10.2.0-next.0) (2026-03-18)
7
+
8
+ ### Features
9
+
10
+ - **ebsr:** add trace log for scoring in outcome function PD-5456 ([c83e1c2](https://github.com/pie-framework/pie-elements/commit/c83e1c29c8a0e7a03e3479cd00e9321b1e3f9edc))
11
+
6
12
  ## [10.1.1-next.1](https://github.com/pie-framework/pie-elements/compare/@pie-element/ebsr-controller@10.1.0-next.2...@pie-element/ebsr-controller@10.1.1-next.1) (2026-02-26)
7
13
 
8
14
  **Note:** Version bump only for package @pie-element/ebsr-controller
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.createDefaultModel = exports.createCorrectResponseSession = void 0;
7
+ exports.getLogTrace = exports.createDefaultModel = exports.createCorrectResponseSession = void 0;
8
8
  exports.model = model;
9
9
  exports.normalize = void 0;
10
10
  exports.outcome = outcome;
@@ -192,6 +192,69 @@ const getScore = (config, sessionPart, key, partialScoringEnabled) => {
192
192
  }
193
193
  return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);
194
194
  };
195
+
196
+ /**
197
+ * Generates detailed trace log for math-templated scoring evaluation
198
+ * @param {Object} question
199
+ * @param {Object} session
200
+ * @param {Object} env
201
+ * @returns {Array<string>} traceLog
202
+ */
203
+ const getLogTrace = (question, session, env) => {
204
+ const traceLog = [];
205
+ if (!session || !session.value) {
206
+ traceLog.push('Student did not answer the question.');
207
+ return traceLog;
208
+ }
209
+ const {
210
+ value
211
+ } = session;
212
+ const {
213
+ partA,
214
+ partB
215
+ } = value;
216
+ const partialScoringEnabled = _controllerUtils.partialScoring.enabled(question, env);
217
+ traceLog.push(`Scoring method: ${partialScoringEnabled ? 'partial scoring' : 'all-or-nothing scoring'}.`);
218
+ const partAquestionType = question.partA.choiceMode === 'radio' ? 'multiple-choice (radio)' : 'multiple-select (checkbox)';
219
+ traceLog.push(`Part A question type: ${partAquestionType}.`);
220
+ const partASelections = partA?.value || [];
221
+ const partACorrectChoices = (question.partA.choices || []).filter(c => c.correct);
222
+ const partACorrectValues = partACorrectChoices.map(c => c.value);
223
+ const partACorrectSelected = partASelections.filter(v => partACorrectValues.includes(v));
224
+ const partAIncorrectSelected = partASelections.filter(v => !partACorrectValues.includes(v));
225
+ if (partASelections.length) {
226
+ traceLog.push(`Part A: student selected ${partASelections.length} choice(s) (${partACorrectSelected.length} correct, ${partAIncorrectSelected.length} incorrect).`);
227
+ }
228
+ const scoreA = getScore(question, partA, 'partA', partialScoringEnabled);
229
+ traceLog.push(`Part A score: ${scoreA}.`);
230
+ const partBquestionType = question.partB.choiceMode === 'radio' ? 'multiple-choice (radio)' : 'multiple-select (checkbox)';
231
+ traceLog.push(`Part B question type: ${partBquestionType}.`);
232
+ const partBSelections = partB?.value || [];
233
+ const partBCorrectChoices = (question.partB.choices || []).filter(c => c.correct);
234
+ const partBCorrectValues = partBCorrectChoices.map(c => c.value);
235
+ const correctSelected = partBSelections.filter(v => partBCorrectValues.includes(v));
236
+ const incorrectSelected = partBSelections.filter(v => !partBCorrectValues.includes(v));
237
+ if (partBSelections.length) {
238
+ traceLog.push(`Part B: student selected ${partBSelections.length} choice(s) (${correctSelected.length} correct, ${incorrectSelected.length} incorrect).`);
239
+ }
240
+ const scoreB = getScore(question, partB, 'partB', partialScoringEnabled);
241
+ traceLog.push(`Part B score: ${scoreB}.`);
242
+ if (!partialScoringEnabled) {
243
+ traceLog.push('Final score is awarded only if both Part A and Part B are completely correct.');
244
+ traceLog.push(`Final score: ${scoreA === 1 && scoreB === 1 ? 1 : 0}.`);
245
+ } else {
246
+ traceLog.push('With partial scoring enabled, Part A must be correct to earn any credit.');
247
+ let finalScore = 0;
248
+ if (scoreA === 1 && scoreB === 1) {
249
+ finalScore = 2;
250
+ } else if (scoreA === 1 && scoreB < 1) {
251
+ finalScore = 1;
252
+ }
253
+ traceLog.push(`Final score: ${finalScore}.`);
254
+ }
255
+ return traceLog;
256
+ };
257
+ exports.getLogTrace = getLogTrace;
195
258
  function outcome(config, session, env) {
196
259
  return new Promise(resolve => {
197
260
  const {
@@ -202,7 +265,8 @@ function outcome(config, session, env) {
202
265
  score: 0,
203
266
  scoreA: 0,
204
267
  scoreB: 0,
205
- empty: true
268
+ empty: true,
269
+ logTrace: ['Student did not answer the question.']
206
270
  });
207
271
  }
208
272
  if (value) {
@@ -213,6 +277,7 @@ function outcome(config, session, env) {
213
277
  const partialScoringEnabled = _controllerUtils.partialScoring.enabled(config, env);
214
278
  const scoreA = getScore(config, partA, 'partA', partialScoringEnabled);
215
279
  const scoreB = getScore(config, partB, 'partB', partialScoringEnabled);
280
+ const logTrace = getLogTrace(config, session, env);
216
281
  if (!partialScoringEnabled) {
217
282
  // The EBSR item is worth 1 point
218
283
  // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded
@@ -220,7 +285,8 @@ function outcome(config, session, env) {
220
285
  score: scoreA === 1 && scoreB === 1 ? 1 : 0,
221
286
  scoreA,
222
287
  scoreB,
223
- max: 1
288
+ max: 1,
289
+ logTrace
224
290
  });
225
291
  } else {
226
292
  // The EBSR item is worth 2 points
@@ -231,7 +297,8 @@ function outcome(config, session, env) {
231
297
  score: 2,
232
298
  scoreA,
233
299
  scoreB,
234
- max: 2
300
+ max: 2,
301
+ logTrace
235
302
  });
236
303
  } else {
237
304
  // If Part A is correct and part B is incorrect, 1 point is awarded
@@ -239,7 +306,8 @@ function outcome(config, session, env) {
239
306
  score: 1,
240
307
  scoreA,
241
308
  scoreB,
242
- max: 2
309
+ max: 2,
310
+ logTrace
243
311
  });
244
312
  }
245
313
  } else {
@@ -248,7 +316,8 @@ function outcome(config, session, env) {
248
316
  score: 0,
249
317
  scoreA,
250
318
  scoreB,
251
- max: 2
319
+ max: 2,
320
+ logTrace
252
321
  });
253
322
  }
254
323
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_defaults","_interopRequireDefault","require","_controllerUtils","_utils","_lodashEs","_translator","translator","Translator","prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","isResponseCorrect","undefined","normalizePart","base","choicesLayout","verticalMode","normalize","partA","partB","language","question","defaults","exports","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","get","partALockChoiceOrder","lockChoices","partAChoices","partBChoices","getShuffledChoices","partBSession","partBLockChoiceOrder","isEmpty","catch","e","console","error","partLabels","partLabel","t","lng","index","partLabelType","teacherInstructions","teacherInstructionsEnabled","prompt","promptEnabled","extraCSSRules","createDefaultModel","isCorrect","getScore","config","sessionPart","partialScoringEnabled","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","parseFloat","toFixed","outcome","score","scoreA","scoreB","empty","partialScoring","enabled","max","returnPartCorrect","answers","forEach","i","push","createCorrectResponseSession","partACorrect","partBCorrect","getInnerText","html","replaceAll","getContent","replace","validatePart","minAnswerChoices","maxAnswerChoices","reversedChoices","reverse","errors","choicesErrors","rationaleErrors","hasCorrectResponse","field","required","identicalAnswer","slice","some","nbOfChoices","answerChoices","correctResponse","validate","partAConfig","partBConfig","partAErrors","partBErrors"],"sources":["../src/index.js"],"sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices, partialScoring } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport { get, isEmpty } from 'lodash-es';\nimport Translator from '@pie-lib/translator';\n\nconst { translator } = Translator;\n\nconst prepareChoice = (model, env, defaultFeedback) => (choice) => {\n const out = {\n label: choice.label,\n value: choice.value,\n };\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign({ correct: 'Correct', incorrect: 'Incorrect' }, part.defaultFeedback);\n\n let choices = part.choices ? part.choices.map(prepareChoice(part, env, defaultFeedback)) : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter((c) => c.correct).length,\n },\n responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(part, key, session) : undefined,\n };\n};\n\nconst normalizePart = (model, base) => ({\n ...base,\n ...model,\n choicesLayout: model.choicesLayout || (model.verticalMode === false && 'horizontal') || 'vertical',\n});\n\nexport const normalize = ({ partA = {}, partB = {}, language, ...question }) => ({\n ...defaults,\n ...question,\n partA: normalizePart(partA, { ...defaults.partA, language }),\n partB: normalizePart(partB, { ...defaults.partB, language }),\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = (part) => (id, element, update) =>\n new Promise((resolve) => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value',\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value',\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues,\n }).catch((e) => {\n // eslint-disable-next-line no-console\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n const language = normalizedQuestion.language;\n partA.partLabel = translator.t('ebsr.part', {\n lng: language,\n index: normalizedQuestion.partLabelType === 'Letters' ? 'A' : '1',\n });\n partB.partLabel = translator.t('ebsr.part', {\n lng: language,\n index: normalizedQuestion.partLabelType === 'Letters' ? 'B' : '2',\n });\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n partA.teacherInstructions = normalizedQuestion.partA.teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB.teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled ? normalizedQuestion.partA.prompt : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled ? normalizedQuestion.partB.prompt : null;\n\n return new Promise((resolve) => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n extraCSSRules: normalizedQuestion.extraCSSRules,\n partA,\n partB,\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise((resolve) => {\n resolve({\n ...defaults,\n ...model,\n });\n });\n\nconst isCorrect = (c) => c.correct === true;\n\nconst getScore = (config, sessionPart, key, partialScoringEnabled) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = (c) => !!(sessionPartValue || []).find((v) => v === c.value);\n const correctAndNotChosen = (c) => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = (c) => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!partialScoringEnabled && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\nexport function outcome(config, session, env) {\n return new Promise((resolve) => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const partialScoringEnabled = partialScoring.enabled(config, env);\n\n const scoreA = getScore(config, partA, 'partA', partialScoringEnabled);\n const scoreB = getScore(config, partB, 'partB', partialScoringEnabled);\n\n if (!partialScoringEnabled) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: scoreA === 1 && scoreB === 1 ? 1 : 0, scoreA, scoreB, max: 1 });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2 });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2 });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2 });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = (choices) => {\n let answers = [];\n\n choices.forEach((i) => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect,\n },\n partB: {\n id: 'partB',\n value: partBCorrect,\n },\n },\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nconst validatePart = (model = {}, config = {}) => {\n const { choices } = model;\n const { minAnswerChoices = 2, maxAnswerChoices } = config;\n const reversedChoices = [...(choices || [])].reverse();\n const errors = {};\n const choicesErrors = {};\n const rationaleErrors = {};\n let hasCorrectResponse = false;\n\n ['teacherInstructions', 'prompt'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n reversedChoices.forEach((choice, index) => {\n const { correct, value, label, rationale } = choice;\n\n if (correct) {\n hasCorrectResponse = true;\n }\n\n if (!getContent(label)) {\n choicesErrors[value] = 'Content should not be empty.';\n } else {\n const identicalAnswer = reversedChoices.slice(index + 1).some((c) => c.label === label);\n\n if (identicalAnswer) {\n choicesErrors[value] = 'Content should be unique.';\n }\n }\n\n if (config.rationale?.required && !getContent(rationale)) {\n rationaleErrors[value] = 'This field is required.';\n }\n });\n\n const nbOfChoices = (choices || []).length;\n\n if (nbOfChoices < minAnswerChoices) {\n errors.answerChoices = `There should be at least ${minAnswerChoices} choices defined.`;\n } else if (nbOfChoices > maxAnswerChoices) {\n errors.answerChoices = `No more than ${maxAnswerChoices} choices should be defined.`;\n }\n\n if (!hasCorrectResponse) {\n errors.correctResponse = 'No correct response defined.';\n }\n\n if (!isEmpty(choicesErrors)) {\n errors.choices = choicesErrors;\n }\n\n if (!isEmpty(rationaleErrors)) {\n errors.rationale = rationaleErrors;\n }\n\n return errors;\n};\n\nexport const validate = (model = {}, config = {}) => {\n const { partA, partB } = model || {};\n const { partA: partAConfig, partB: partBConfig } = config || {};\n\n const partAErrors = validatePart(partA, partAConfig);\n const partBErrors = validatePart(partB, partBConfig);\n\n return { partA: partAErrors, partB: partBErrors };\n};\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,SAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,gBAAA,GAAAD,OAAA;AACA,IAAAE,MAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AACA,IAAAI,WAAA,GAAAL,sBAAA,CAAAC,OAAA;AAEA,MAAM;EAAEK;AAAW,CAAC,GAAGC,mBAAU;AAEjC,MAAMC,aAAa,GAAGA,CAACC,KAAK,EAAEC,GAAG,EAAEC,eAAe,KAAMC,MAAM,IAAK;EACjE,MAAMC,GAAG,GAAG;IACVC,KAAK,EAAEF,MAAM,CAACE,KAAK;IACnBC,KAAK,EAAEH,MAAM,CAACG;EAChB,CAAC;EAED,IAAIL,GAAG,CAACM,IAAI,KAAK,YAAY,KAAKN,GAAG,CAACO,IAAI,KAAK,MAAM,IAAIP,GAAG,CAACO,IAAI,KAAK,UAAU,CAAC,EAAE;IACjFJ,GAAG,CAACK,SAAS,GAAGT,KAAK,CAACU,gBAAgB,GAAGP,MAAM,CAACM,SAAS,GAAG,IAAI;EAClE,CAAC,MAAM;IACLL,GAAG,CAACK,SAAS,GAAG,IAAI;EACtB;EAEA,IAAIR,GAAG,CAACO,IAAI,KAAK,UAAU,EAAE;IAC3BJ,GAAG,CAACO,OAAO,GAAG,CAAC,CAACR,MAAM,CAACQ,OAAO;IAE9B,IAAIX,KAAK,CAACY,eAAe,EAAE;MACzB,MAAMC,YAAY,GAAIV,MAAM,CAACW,QAAQ,IAAIX,MAAM,CAACW,QAAQ,CAACC,IAAI,IAAK,MAAM;MAExE,IAAIF,YAAY,KAAK,SAAS,EAAE;QAC9BT,GAAG,CAACU,QAAQ,GAAGZ,eAAe,CAACC,MAAM,CAACQ,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;MAC1E,CAAC,MAAM,IAAIE,YAAY,KAAK,QAAQ,EAAE;QACpCT,GAAG,CAACU,QAAQ,GAAGX,MAAM,CAACW,QAAQ,CAACR,KAAK;MACtC;IACF;EACF;EAEA,OAAOF,GAAG;AACZ,CAAC;AAED,MAAMY,SAAS,GAAGA,CAACC,IAAI,EAAEC,GAAG,EAAEC,OAAO,EAAElB,GAAG,KAAK;EAC7C,MAAMC,eAAe,GAAGkB,MAAM,CAACC,MAAM,CAAC;IAAEV,OAAO,EAAE,SAAS;IAAEW,SAAS,EAAE;EAAY,CAAC,EAAEL,IAAI,CAACf,eAAe,CAAC;EAE3G,IAAIqB,OAAO,GAAGN,IAAI,CAACM,OAAO,GAAGN,IAAI,CAACM,OAAO,CAACC,GAAG,CAACzB,aAAa,CAACkB,IAAI,EAAEhB,GAAG,EAAEC,eAAe,CAAC,CAAC,GAAG,EAAE;EAE7F,OAAO;IACL,GAAGe,IAAI;IACPM,OAAO;IACPE,QAAQ,EAAExB,GAAG,CAACO,IAAI,KAAK,QAAQ;IAC/BkB,QAAQ,EAAE;MACRC,GAAG,EAAEV,IAAI,CAACM,OAAO,CAACK,MAAM,CAAEC,CAAC,IAAKA,CAAC,CAAClB,OAAO,CAAC,CAACmB;IAC7C,CAAC;IACDC,eAAe,EAAE9B,GAAG,CAACO,IAAI,KAAK,UAAU,GAAG,IAAAwB,wBAAiB,EAACf,IAAI,EAAEC,GAAG,EAAEC,OAAO,CAAC,GAAGc;EACrF,CAAC;AACH,CAAC;AAED,MAAMC,aAAa,GAAGA,CAAClC,KAAK,EAAEmC,IAAI,MAAM;EACtC,GAAGA,IAAI;EACP,GAAGnC,KAAK;EACRoC,aAAa,EAAEpC,KAAK,CAACoC,aAAa,IAAKpC,KAAK,CAACqC,YAAY,KAAK,KAAK,IAAI,YAAa,IAAI;AAC1F,CAAC,CAAC;AAEK,MAAMC,SAAS,GAAGA,CAAC;EAAEC,KAAK,GAAG,CAAC,CAAC;EAAEC,KAAK,GAAG,CAAC,CAAC;EAAEC,QAAQ;EAAE,GAAGC;AAAS,CAAC,MAAM;EAC/E,GAAGC,iBAAQ;EACX,GAAGD,QAAQ;EACXH,KAAK,EAAEL,aAAa,CAACK,KAAK,EAAE;IAAE,GAAGI,iBAAQ,CAACJ,KAAK;IAAEE;EAAS,CAAC,CAAC;EAC5DD,KAAK,EAAEN,aAAa,CAACM,KAAK,EAAE;IAAE,GAAGG,iBAAQ,CAACH,KAAK;IAAEC;EAAS,CAAC;AAC7D,CAAC,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AANAG,OAAA,CAAAN,SAAA,GAAAA,SAAA;AAOO,eAAetC,KAAKA,CAAC0C,QAAQ,EAAEvB,OAAO,EAAElB,GAAG,EAAE4C,aAAa,EAAE;EACjE,MAAMC,kBAAkB,GAAGR,SAAS,CAACI,QAAQ,CAAC;EAC9C,MAAMH,KAAK,GAAGvB,SAAS,CAAC8B,kBAAkB,CAACP,KAAK,EAAE,OAAO,EAAEpB,OAAO,EAAElB,GAAG,CAAC;EACxE,MAAMuC,KAAK,GAAGxB,SAAS,CAAC8B,kBAAkB,CAACN,KAAK,EAAE,OAAO,EAAErB,OAAO,EAAElB,GAAG,CAAC;EAExE,MAAM8C,cAAc,GAAG,CAAC,CAAC;EAEzB,MAAMC,EAAE,GAAI/B,IAAI,IAAK,CAACgC,EAAE,EAAEC,OAAO,EAAEC,MAAM,KACvC,IAAIC,OAAO,CAAEC,OAAO,IAAK;IACvBN,cAAc,CAAC9B,IAAI,CAAC,GAAGkC,MAAM,CAACJ,cAAc;IAC5CM,OAAO,CAAC,CAAC;EACX,CAAC,CAAC;EAEJ,MAAMC,YAAY,GAAG,IAAAC,aAAG,EAACpC,OAAO,EAAE,aAAa,CAAC;EAChD,MAAMqC,oBAAoB,GAAG,IAAAC,4BAAW,EAACX,kBAAkB,CAACP,KAAK,EAAEe,YAAY,EAAErD,GAAG,CAAC;EAErF,MAAM;IAAEsB,OAAO,EAAEmC;EAAa,CAAC,GAAGnB,KAAK,IAAI,CAAC,CAAC;EAC7C,MAAM;IAAEhB,OAAO,EAAEoC;EAAa,CAAC,GAAGnB,KAAK,IAAI,CAAC,CAAC;EAE7C,IAAI,CAACgB,oBAAoB,IAAIE,YAAY,IAAIA,YAAY,CAAC5B,MAAM,EAAE;IAChES,KAAK,CAAChB,OAAO,GAAG,MAAM,IAAAqC,mCAAkB,EACtCF,YAAY,EACZ;MAAEX,cAAc,EAAE,CAAC5B,OAAO,CAAC4B,cAAc,IAAI,CAAC,CAAC,EAAER;IAAM,CAAC,EACxDS,EAAE,CAAC,OAAO,CAAC,EACX,OACF,CAAC;EACH;EAEA,MAAMa,YAAY,GAAG,IAAAN,aAAG,EAACpC,OAAO,EAAE,aAAa,CAAC;EAChD,MAAM2C,oBAAoB,GAAG,IAAAL,4BAAW,EAACX,kBAAkB,CAACN,KAAK,EAAEqB,YAAY,EAAE5D,GAAG,CAAC;EAErF,IAAI,CAAC6D,oBAAoB,IAAIH,YAAY,IAAIA,YAAY,CAAC7B,MAAM,EAAE;IAChEU,KAAK,CAACjB,OAAO,GAAG,MAAM,IAAAqC,mCAAkB,EACtCD,YAAY,EACZ;MAAEZ,cAAc,EAAE,CAAC5B,OAAO,CAAC4B,cAAc,IAAI,CAAC,CAAC,EAAEP;IAAM,CAAC,EACxDQ,EAAE,CAAC,OAAO,CAAC,EACX,OACF,CAAC;EACH;EAEA,IAAI,CAAC,IAAAe,iBAAO,EAAChB,cAAc,CAAC,EAAE;IAC5B,IAAIF,aAAa,IAAI,OAAOA,aAAa,KAAK,UAAU,EAAE;MACxDA,aAAa,CAAC1B,OAAO,CAAC8B,EAAE,EAAE9B,OAAO,CAAC+B,OAAO,EAAE;QACzCH;MACF,CAAC,CAAC,CAACiB,KAAK,CAAEC,CAAC,IAAK;QACd;QACAC,OAAO,CAACC,KAAK,CAAC,uBAAuB,EAAEF,CAAC,CAAC;MAC3C,CAAC,CAAC;IACJ;EACF;EAEA,IAAInB,kBAAkB,CAACsB,UAAU,EAAE;IACjC,MAAM3B,QAAQ,GAAGK,kBAAkB,CAACL,QAAQ;IAC5CF,KAAK,CAAC8B,SAAS,GAAGxE,UAAU,CAACyE,CAAC,CAAC,WAAW,EAAE;MAC1CC,GAAG,EAAE9B,QAAQ;MACb+B,KAAK,EAAE1B,kBAAkB,CAAC2B,aAAa,KAAK,SAAS,GAAG,GAAG,GAAG;IAChE,CAAC,CAAC;IACFjC,KAAK,CAAC6B,SAAS,GAAGxE,UAAU,CAACyE,CAAC,CAAC,WAAW,EAAE;MAC1CC,GAAG,EAAE9B,QAAQ;MACb+B,KAAK,EAAE1B,kBAAkB,CAAC2B,aAAa,KAAK,SAAS,GAAG,GAAG,GAAG;IAChE,CAAC,CAAC;EACJ,CAAC,MAAM;IACLlC,KAAK,CAAC8B,SAAS,GAAGpC,SAAS;IAC3BO,KAAK,CAAC6B,SAAS,GAAGpC,SAAS;EAC7B;EAEA,IAAIhC,GAAG,CAACM,IAAI,KAAK,YAAY,KAAKN,GAAG,CAACO,IAAI,KAAK,MAAM,IAAIP,GAAG,CAACO,IAAI,KAAK,UAAU,CAAC,EAAE;IACjF+B,KAAK,CAACmC,mBAAmB,GAAG5B,kBAAkB,CAACP,KAAK,CAACoC,0BAA0B,GAC3E7B,kBAAkB,CAACP,KAAK,CAACmC,mBAAmB,GAC5C,IAAI;IACRlC,KAAK,CAACkC,mBAAmB,GAAG5B,kBAAkB,CAACN,KAAK,CAACmC,0BAA0B,GAC3E7B,kBAAkB,CAACN,KAAK,CAACkC,mBAAmB,GAC5C,IAAI;EACV,CAAC,MAAM;IACLnC,KAAK,CAACmC,mBAAmB,GAAG,IAAI;IAChClC,KAAK,CAACkC,mBAAmB,GAAG,IAAI;EAClC;EAEAnC,KAAK,CAACqC,MAAM,GAAG9B,kBAAkB,CAACP,KAAK,CAACsC,aAAa,GAAG/B,kBAAkB,CAACP,KAAK,CAACqC,MAAM,GAAG,IAAI;EAC9FpC,KAAK,CAACoC,MAAM,GAAG9B,kBAAkB,CAACN,KAAK,CAACqC,aAAa,GAAG/B,kBAAkB,CAACN,KAAK,CAACoC,MAAM,GAAG,IAAI;EAE9F,OAAO,IAAIxB,OAAO,CAAEC,OAAO,IAAK;IAC9BA,OAAO,CAAC;MACN5B,QAAQ,EAAExB,GAAG,CAACO,IAAI,KAAK,QAAQ;MAC/BA,IAAI,EAAEP,GAAG,CAACO,IAAI;MACdsE,aAAa,EAAEhC,kBAAkB,CAACgC,aAAa;MAC/CvC,KAAK;MACLC;IACF,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ;AAEO,MAAMuC,kBAAkB,GAAGA,CAAC/E,KAAK,GAAG,CAAC,CAAC,KAC3C,IAAIoD,OAAO,CAAEC,OAAO,IAAK;EACvBA,OAAO,CAAC;IACN,GAAGV,iBAAQ;IACX,GAAG3C;EACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAAC4C,OAAA,CAAAmC,kBAAA,GAAAA,kBAAA;AAEL,MAAMC,SAAS,GAAInD,CAAC,IAAKA,CAAC,CAAClB,OAAO,KAAK,IAAI;AAE3C,MAAMsE,QAAQ,GAAGA,CAACC,MAAM,EAAEC,WAAW,EAAEjE,GAAG,EAAEkE,qBAAqB,KAAK;EACpE,MAAM;IAAE7D,OAAO,GAAG;EAAG,CAAC,GAAI2D,MAAM,IAAIA,MAAM,CAAChE,GAAG,CAAC,IAAK,CAAC,CAAC;EACtD,MAAMmE,QAAQ,GAAG9D,OAAO,CAACO,MAAM;EAC/B,MAAM;IAAExB,KAAK,EAAEgF;EAAiB,CAAC,GAAGH,WAAW,IAAI,CAAC,CAAC;EAErD,MAAMI,MAAM,GAAI1D,CAAC,IAAK,CAAC,CAAC,CAACyD,gBAAgB,IAAI,EAAE,EAAEE,IAAI,CAAEC,CAAC,IAAKA,CAAC,KAAK5D,CAAC,CAACvB,KAAK,CAAC;EAC3E,MAAMoF,mBAAmB,GAAI7D,CAAC,IAAKmD,SAAS,CAACnD,CAAC,CAAC,IAAI,CAAC0D,MAAM,CAAC1D,CAAC,CAAC;EAC7D,MAAM8D,kBAAkB,GAAI9D,CAAC,IAAK,CAACmD,SAAS,CAACnD,CAAC,CAAC,IAAI0D,MAAM,CAAC1D,CAAC,CAAC;EAC5D,MAAM+D,cAAc,GAAGrE,OAAO,CAACsE,MAAM,CAAC,CAACC,KAAK,EAAE3F,MAAM,KAAK;IACvD,IAAIuF,mBAAmB,CAACvF,MAAM,CAAC,IAAIwF,kBAAkB,CAACxF,MAAM,CAAC,EAAE;MAC7D,OAAO2F,KAAK,GAAG,CAAC;IAClB,CAAC,MAAM;MACL,OAAOA,KAAK;IACd;EACF,CAAC,EAAEvE,OAAO,CAACO,MAAM,CAAC;;EAElB;EACA,IAAI,CAACsD,qBAAqB,IAAIQ,cAAc,GAAGP,QAAQ,EAAE;IACvD,OAAO,CAAC;EACV;EAEA,OAAOU,UAAU,CAACV,QAAQ,GAAG,CAACO,cAAc,GAAGP,QAAQ,EAAEW,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC1E,CAAC;AAEM,SAASC,OAAOA,CAACf,MAAM,EAAE/D,OAAO,EAAElB,GAAG,EAAE;EAC5C,OAAO,IAAImD,OAAO,CAAEC,OAAO,IAAK;IAC9B,MAAM;MAAE/C;IAAM,CAAC,GAAGa,OAAO,IAAI,CAAC,CAAC;IAE/B,IAAI,CAACA,OAAO,IAAI,CAACb,KAAK,EAAE;MACtB+C,OAAO,CAAC;QAAE6C,KAAK,EAAE,CAAC;QAAEC,MAAM,EAAE,CAAC;QAAEC,MAAM,EAAE,CAAC;QAAEC,KAAK,EAAE;MAAK,CAAC,CAAC;IAC1D;IAEA,IAAI/F,KAAK,EAAE;MACT,MAAM;QAAEiC,KAAK;QAAEC;MAAM,CAAC,GAAGlC,KAAK,IAAI,CAAC,CAAC;MAEpC,MAAM8E,qBAAqB,GAAGkB,+BAAc,CAACC,OAAO,CAACrB,MAAM,EAAEjF,GAAG,CAAC;MAEjE,MAAMkG,MAAM,GAAGlB,QAAQ,CAACC,MAAM,EAAE3C,KAAK,EAAE,OAAO,EAAE6C,qBAAqB,CAAC;MACtE,MAAMgB,MAAM,GAAGnB,QAAQ,CAACC,MAAM,EAAE1C,KAAK,EAAE,OAAO,EAAE4C,qBAAqB,CAAC;MAEtE,IAAI,CAACA,qBAAqB,EAAE;QAC1B;QACA;QACA/B,OAAO,CAAC;UAAE6C,KAAK,EAAEC,MAAM,KAAK,CAAC,IAAIC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;UAAED,MAAM;UAAEC,MAAM;UAAEI,GAAG,EAAE;QAAE,CAAC,CAAC;MAClF,CAAC,MAAM;QACL;QACA,IAAIL,MAAM,KAAK,CAAC,EAAE;UAChB,IAAIC,MAAM,KAAK,CAAC,EAAE;YAChB;YACA/C,OAAO,CAAC;cAAE6C,KAAK,EAAE,CAAC;cAAEC,MAAM;cAAEC,MAAM;cAAEI,GAAG,EAAE;YAAE,CAAC,CAAC;UAC/C,CAAC,MAAM;YACL;YACAnD,OAAO,CAAC;cAAE6C,KAAK,EAAE,CAAC;cAAEC,MAAM;cAAEC,MAAM;cAAEI,GAAG,EAAE;YAAE,CAAC,CAAC;UAC/C;QACF,CAAC,MAAM;UACL;UACAnD,OAAO,CAAC;YAAE6C,KAAK,EAAE,CAAC;YAAEC,MAAM;YAAEC,MAAM;YAAEI,GAAG,EAAE;UAAE,CAAC,CAAC;QAC/C;MACF;IACF;EACF,CAAC,CAAC;AACJ;AAEA,MAAMC,iBAAiB,GAAIlF,OAAO,IAAK;EACrC,IAAImF,OAAO,GAAG,EAAE;EAEhBnF,OAAO,CAACoF,OAAO,CAAEC,CAAC,IAAK;IACrB,MAAM;MAAEjG,OAAO;MAAEL;IAAM,CAAC,GAAGsG,CAAC;IAC5B,IAAIjG,OAAO,EAAE;MACX+F,OAAO,CAACG,IAAI,CAACvG,KAAK,CAAC;IACrB;EACF,CAAC,CAAC;EACF,OAAOoG,OAAO;AAChB,CAAC;AAEM,MAAMI,4BAA4B,GAAGA,CAACpE,QAAQ,EAAEzC,GAAG,KAAK;EAC7D,OAAO,IAAImD,OAAO,CAAEC,OAAO,IAAK;IAC9B,IAAIpD,GAAG,CAACO,IAAI,KAAK,UAAU,IAAIP,GAAG,CAACM,IAAI,KAAK,YAAY,EAAE;MACxD,MAAM;QAAEgC,KAAK;QAAEC;MAAM,CAAC,GAAGE,QAAQ;MAEjC,MAAMqE,YAAY,GAAGN,iBAAiB,CAAClE,KAAK,CAAChB,OAAO,CAAC;MACrD,MAAMyF,YAAY,GAAGP,iBAAiB,CAACjE,KAAK,CAACjB,OAAO,CAAC;MAErD8B,OAAO,CAAC;QACN/C,KAAK,EAAE;UACLiC,KAAK,EAAE;YACLU,EAAE,EAAE,OAAO;YACX3C,KAAK,EAAEyG;UACT,CAAC;UACDvE,KAAK,EAAE;YACLS,EAAE,EAAE,OAAO;YACX3C,KAAK,EAAE0G;UACT;QACF,CAAC;QACD/D,EAAE,EAAE;MACN,CAAC,CAAC;IACJ,CAAC,MAAM;MACLI,OAAO,CAAC,IAAI,CAAC;IACf;EACF,CAAC,CAAC;AACJ,CAAC;;AAED;AAAAT,OAAA,CAAAkE,4BAAA,GAAAA,4BAAA;AACA,MAAMG,YAAY,GAAIC,IAAI,IAAK,CAACA,IAAI,IAAI,EAAE,EAAEC,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC;;AAEtE;AACA,MAAMC,UAAU,GAAIF,IAAI,IAAK,CAACA,IAAI,IAAI,EAAE,EAAEG,OAAO,CAAC,oCAAoC,EAAE,EAAE,CAAC;AAE3F,MAAMC,YAAY,GAAGA,CAACtH,KAAK,GAAG,CAAC,CAAC,EAAEkF,MAAM,GAAG,CAAC,CAAC,KAAK;EAChD,MAAM;IAAE3D;EAAQ,CAAC,GAAGvB,KAAK;EACzB,MAAM;IAAEuH,gBAAgB,GAAG,CAAC;IAAEC;EAAiB,CAAC,GAAGtC,MAAM;EACzD,MAAMuC,eAAe,GAAG,CAAC,IAAIlG,OAAO,IAAI,EAAE,CAAC,CAAC,CAACmG,OAAO,CAAC,CAAC;EACtD,MAAMC,MAAM,GAAG,CAAC,CAAC;EACjB,MAAMC,aAAa,GAAG,CAAC,CAAC;EACxB,MAAMC,eAAe,GAAG,CAAC,CAAC;EAC1B,IAAIC,kBAAkB,GAAG,KAAK;EAE9B,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAACnB,OAAO,CAAEoB,KAAK,IAAK;IACnD,IAAI7C,MAAM,CAAC6C,KAAK,CAAC,EAAEC,QAAQ,IAAI,CAACZ,UAAU,CAACpH,KAAK,CAAC+H,KAAK,CAAC,CAAC,EAAE;MACxDJ,MAAM,CAACI,KAAK,CAAC,GAAG,yBAAyB;IAC3C;EACF,CAAC,CAAC;EAEFN,eAAe,CAACd,OAAO,CAAC,CAACxG,MAAM,EAAEqE,KAAK,KAAK;IACzC,MAAM;MAAE7D,OAAO;MAAEL,KAAK;MAAED,KAAK;MAAEI;IAAU,CAAC,GAAGN,MAAM;IAEnD,IAAIQ,OAAO,EAAE;MACXmH,kBAAkB,GAAG,IAAI;IAC3B;IAEA,IAAI,CAACV,UAAU,CAAC/G,KAAK,CAAC,EAAE;MACtBuH,aAAa,CAACtH,KAAK,CAAC,GAAG,8BAA8B;IACvD,CAAC,MAAM;MACL,MAAM2H,eAAe,GAAGR,eAAe,CAACS,KAAK,CAAC1D,KAAK,GAAG,CAAC,CAAC,CAAC2D,IAAI,CAAEtG,CAAC,IAAKA,CAAC,CAACxB,KAAK,KAAKA,KAAK,CAAC;MAEvF,IAAI4H,eAAe,EAAE;QACnBL,aAAa,CAACtH,KAAK,CAAC,GAAG,2BAA2B;MACpD;IACF;IAEA,IAAI4E,MAAM,CAACzE,SAAS,EAAEuH,QAAQ,IAAI,CAACZ,UAAU,CAAC3G,SAAS,CAAC,EAAE;MACxDoH,eAAe,CAACvH,KAAK,CAAC,GAAG,yBAAyB;IACpD;EACF,CAAC,CAAC;EAEF,MAAM8H,WAAW,GAAG,CAAC7G,OAAO,IAAI,EAAE,EAAEO,MAAM;EAE1C,IAAIsG,WAAW,GAAGb,gBAAgB,EAAE;IAClCI,MAAM,CAACU,aAAa,GAAG,4BAA4Bd,gBAAgB,mBAAmB;EACxF,CAAC,MAAM,IAAIa,WAAW,GAAGZ,gBAAgB,EAAE;IACzCG,MAAM,CAACU,aAAa,GAAG,gBAAgBb,gBAAgB,6BAA6B;EACtF;EAEA,IAAI,CAACM,kBAAkB,EAAE;IACvBH,MAAM,CAACW,eAAe,GAAG,8BAA8B;EACzD;EAEA,IAAI,CAAC,IAAAvE,iBAAO,EAAC6D,aAAa,CAAC,EAAE;IAC3BD,MAAM,CAACpG,OAAO,GAAGqG,aAAa;EAChC;EAEA,IAAI,CAAC,IAAA7D,iBAAO,EAAC8D,eAAe,CAAC,EAAE;IAC7BF,MAAM,CAAClH,SAAS,GAAGoH,eAAe;EACpC;EAEA,OAAOF,MAAM;AACf,CAAC;AAEM,MAAMY,QAAQ,GAAGA,CAACvI,KAAK,GAAG,CAAC,CAAC,EAAEkF,MAAM,GAAG,CAAC,CAAC,KAAK;EACnD,MAAM;IAAE3C,KAAK;IAAEC;EAAM,CAAC,GAAGxC,KAAK,IAAI,CAAC,CAAC;EACpC,MAAM;IAAEuC,KAAK,EAAEiG,WAAW;IAAEhG,KAAK,EAAEiG;EAAY,CAAC,GAAGvD,MAAM,IAAI,CAAC,CAAC;EAE/D,MAAMwD,WAAW,GAAGpB,YAAY,CAAC/E,KAAK,EAAEiG,WAAW,CAAC;EACpD,MAAMG,WAAW,GAAGrB,YAAY,CAAC9E,KAAK,EAAEiG,WAAW,CAAC;EAEpD,OAAO;IAAElG,KAAK,EAAEmG,WAAW;IAAElG,KAAK,EAAEmG;EAAY,CAAC;AACnD,CAAC;AAAC/F,OAAA,CAAA2F,QAAA,GAAAA,QAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_defaults","_interopRequireDefault","require","_controllerUtils","_utils","_lodashEs","_translator","translator","Translator","prepareChoice","model","env","defaultFeedback","choice","out","label","value","role","mode","rationale","rationaleEnabled","correct","feedbackEnabled","feedbackType","feedback","type","parsePart","part","key","session","Object","assign","incorrect","choices","map","disabled","complete","min","filter","c","length","responseCorrect","isResponseCorrect","undefined","normalizePart","base","choicesLayout","verticalMode","normalize","partA","partB","language","question","defaults","exports","updateSession","normalizedQuestion","shuffledValues","us","id","element","update","Promise","resolve","partASession","get","partALockChoiceOrder","lockChoices","partAChoices","partBChoices","getShuffledChoices","partBSession","partBLockChoiceOrder","isEmpty","catch","e","console","error","partLabels","partLabel","t","lng","index","partLabelType","teacherInstructions","teacherInstructionsEnabled","prompt","promptEnabled","extraCSSRules","createDefaultModel","isCorrect","getScore","config","sessionPart","partialScoringEnabled","maxScore","sessionPartValue","chosen","find","v","correctAndNotChosen","incorrectAndChosen","correctChoices","reduce","total","parseFloat","toFixed","getLogTrace","traceLog","push","partialScoring","enabled","partAquestionType","choiceMode","partASelections","partACorrectChoices","partACorrectValues","partACorrectSelected","includes","partAIncorrectSelected","scoreA","partBquestionType","partBSelections","partBCorrectChoices","partBCorrectValues","correctSelected","incorrectSelected","scoreB","finalScore","outcome","score","empty","logTrace","max","returnPartCorrect","answers","forEach","i","createCorrectResponseSession","partACorrect","partBCorrect","getInnerText","html","replaceAll","getContent","replace","validatePart","minAnswerChoices","maxAnswerChoices","reversedChoices","reverse","errors","choicesErrors","rationaleErrors","hasCorrectResponse","field","required","identicalAnswer","slice","some","nbOfChoices","answerChoices","correctResponse","validate","partAConfig","partBConfig","partAErrors","partBErrors"],"sources":["../src/index.js"],"sourcesContent":["import defaults from './defaults';\nimport { lockChoices, getShuffledChoices, partialScoring } from '@pie-lib/controller-utils';\nimport { isResponseCorrect } from './utils';\nimport { get, isEmpty } from 'lodash-es';\nimport Translator from '@pie-lib/translator';\n\nconst { translator } = Translator;\n\nconst prepareChoice = (model, env, defaultFeedback) => (choice) => {\n const out = {\n label: choice.label,\n value: choice.value,\n };\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.rationale = model.rationaleEnabled ? choice.rationale : null;\n } else {\n out.rationale = null;\n }\n\n if (env.mode === 'evaluate') {\n out.correct = !!choice.correct;\n\n if (model.feedbackEnabled) {\n const feedbackType = (choice.feedback && choice.feedback.type) || 'none';\n\n if (feedbackType === 'default') {\n out.feedback = defaultFeedback[choice.correct ? 'correct' : 'incorrect'];\n } else if (feedbackType === 'custom') {\n out.feedback = choice.feedback.value;\n }\n }\n }\n\n return out;\n};\n\nconst parsePart = (part, key, session, env) => {\n const defaultFeedback = Object.assign({ correct: 'Correct', incorrect: 'Incorrect' }, part.defaultFeedback);\n\n let choices = part.choices ? part.choices.map(prepareChoice(part, env, defaultFeedback)) : [];\n\n return {\n ...part,\n choices,\n disabled: env.mode !== 'gather',\n complete: {\n min: part.choices.filter((c) => c.correct).length,\n },\n responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(part, key, session) : undefined,\n };\n};\n\nconst normalizePart = (model, base) => ({\n ...base,\n ...model,\n choicesLayout: model.choicesLayout || (model.verticalMode === false && 'horizontal') || 'vertical',\n});\n\nexport const normalize = ({ partA = {}, partB = {}, language, ...question }) => ({\n ...defaults,\n ...question,\n partA: normalizePart(partA, { ...defaults.partA, language }),\n partB: normalizePart(partB, { ...defaults.partB, language }),\n});\n\n/**\n *\n * @param {*} question\n * @param {*} session\n * @param {*} env\n * @param {*} updateSession - optional - a function that will set the properties passed into it on the session.\n */\nexport async function model(question, session, env, updateSession) {\n const normalizedQuestion = normalize(question);\n const partA = parsePart(normalizedQuestion.partA, 'partA', session, env);\n const partB = parsePart(normalizedQuestion.partB, 'partB', session, env);\n\n const shuffledValues = {};\n\n const us = (part) => (id, element, update) =>\n new Promise((resolve) => {\n shuffledValues[part] = update.shuffledValues;\n resolve();\n });\n\n const partASession = get(session, 'value.partA');\n const partALockChoiceOrder = lockChoices(normalizedQuestion.partA, partASession, env);\n\n const { choices: partAChoices } = partA || {};\n const { choices: partBChoices } = partB || {};\n\n if (!partALockChoiceOrder && partAChoices && partAChoices.length) {\n partA.choices = await getShuffledChoices(\n partAChoices,\n { shuffledValues: (session.shuffledValues || {}).partA },\n us('partA'),\n 'value',\n );\n }\n\n const partBSession = get(session, 'value.partB');\n const partBLockChoiceOrder = lockChoices(normalizedQuestion.partB, partBSession, env);\n\n if (!partBLockChoiceOrder && partBChoices && partBChoices.length) {\n partB.choices = await getShuffledChoices(\n partBChoices,\n { shuffledValues: (session.shuffledValues || {}).partB },\n us('partB'),\n 'value',\n );\n }\n\n if (!isEmpty(shuffledValues)) {\n if (updateSession && typeof updateSession === 'function') {\n updateSession(session.id, session.element, {\n shuffledValues,\n }).catch((e) => {\n // eslint-disable-next-line no-console\n console.error('update session failed', e);\n });\n }\n }\n\n if (normalizedQuestion.partLabels) {\n const language = normalizedQuestion.language;\n partA.partLabel = translator.t('ebsr.part', {\n lng: language,\n index: normalizedQuestion.partLabelType === 'Letters' ? 'A' : '1',\n });\n partB.partLabel = translator.t('ebsr.part', {\n lng: language,\n index: normalizedQuestion.partLabelType === 'Letters' ? 'B' : '2',\n });\n } else {\n partA.partLabel = undefined;\n partB.partLabel = undefined;\n }\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n partA.teacherInstructions = normalizedQuestion.partA.teacherInstructionsEnabled\n ? normalizedQuestion.partA.teacherInstructions\n : null;\n partB.teacherInstructions = normalizedQuestion.partB.teacherInstructionsEnabled\n ? normalizedQuestion.partB.teacherInstructions\n : null;\n } else {\n partA.teacherInstructions = null;\n partB.teacherInstructions = null;\n }\n\n partA.prompt = normalizedQuestion.partA.promptEnabled ? normalizedQuestion.partA.prompt : null;\n partB.prompt = normalizedQuestion.partB.promptEnabled ? normalizedQuestion.partB.prompt : null;\n\n return new Promise((resolve) => {\n resolve({\n disabled: env.mode !== 'gather',\n mode: env.mode,\n extraCSSRules: normalizedQuestion.extraCSSRules,\n partA,\n partB,\n });\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise((resolve) => {\n resolve({\n ...defaults,\n ...model,\n });\n });\n\nconst isCorrect = (c) => c.correct === true;\n\nconst getScore = (config, sessionPart, key, partialScoringEnabled) => {\n const { choices = [] } = (config && config[key]) || {};\n const maxScore = choices.length;\n const { value: sessionPartValue } = sessionPart || {};\n\n const chosen = (c) => !!(sessionPartValue || []).find((v) => v === c.value);\n const correctAndNotChosen = (c) => isCorrect(c) && !chosen(c);\n const incorrectAndChosen = (c) => !isCorrect(c) && chosen(c);\n const correctChoices = choices.reduce((total, choice) => {\n if (correctAndNotChosen(choice) || incorrectAndChosen(choice)) {\n return total - 1;\n } else {\n return total;\n }\n }, choices.length);\n\n // determine score for a part\n if (!partialScoringEnabled && correctChoices < maxScore) {\n return 0;\n }\n\n return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);\n};\n\n/**\n * Generates detailed trace log for math-templated scoring evaluation\n * @param {Object} question\n * @param {Object} session\n * @param {Object} env\n * @returns {Array<string>} traceLog\n */\nexport const getLogTrace = (question, session, env) => {\n const traceLog = [];\n\n if (!session || !session.value) {\n traceLog.push('Student did not answer the question.');\n return traceLog;\n }\n\n const { value } = session;\n const { partA, partB } = value;\n\n const partialScoringEnabled = partialScoring.enabled(question, env);\n\n traceLog.push(\n `Scoring method: ${partialScoringEnabled ? 'partial scoring' : 'all-or-nothing scoring'}.`\n );\n\n const partAquestionType =\n question.partA.choiceMode === 'radio'\n ? 'multiple-choice (radio)'\n : 'multiple-select (checkbox)';\n traceLog.push(`Part A question type: ${partAquestionType}.`);\n\n const partASelections = partA?.value || [];\n const partACorrectChoices = (question.partA.choices || []).filter((c) => c.correct);\n const partACorrectValues = partACorrectChoices.map((c) => c.value);\n const partACorrectSelected = partASelections.filter((v) => partACorrectValues.includes(v));\n const partAIncorrectSelected = partASelections.filter((v) => !partACorrectValues.includes(v));\n\n if (partASelections.length) {\n traceLog.push(\n `Part A: student selected ${partASelections.length} choice(s) (${partACorrectSelected.length} correct, ${partAIncorrectSelected.length} incorrect).`\n );\n }\n \n const scoreA = getScore(question, partA, 'partA', partialScoringEnabled);\n traceLog.push(`Part A score: ${scoreA}.`);\n\n const partBquestionType =\n question.partB.choiceMode === 'radio'\n ? 'multiple-choice (radio)'\n : 'multiple-select (checkbox)';\n traceLog.push(`Part B question type: ${partBquestionType}.`);\n\n const partBSelections = partB?.value || [];\n const partBCorrectChoices = (question.partB.choices || []).filter((c) => c.correct);\n const partBCorrectValues = partBCorrectChoices.map((c) => c.value);\n const correctSelected = partBSelections.filter((v) => partBCorrectValues.includes(v));\n const incorrectSelected = partBSelections.filter((v) => !partBCorrectValues.includes(v));\n\n if (partBSelections.length) {\n traceLog.push(\n `Part B: student selected ${partBSelections.length} choice(s) (${correctSelected.length} correct, ${incorrectSelected.length} incorrect).`\n );\n }\n\n const scoreB = getScore(question, partB, 'partB', partialScoringEnabled);\n traceLog.push(`Part B score: ${scoreB}.`);\n\n if (!partialScoringEnabled) {\n traceLog.push(\n 'Final score is awarded only if both Part A and Part B are completely correct.'\n );\n traceLog.push(`Final score: ${scoreA === 1 && scoreB === 1 ? 1 : 0}.`);\n } else {\n traceLog.push(\n 'With partial scoring enabled, Part A must be correct to earn any credit.'\n );\n\n let finalScore = 0;\n if (scoreA === 1 && scoreB === 1) {\n finalScore = 2;\n } else if (scoreA === 1 && scoreB < 1) {\n finalScore = 1;\n }\n\n traceLog.push(`Final score: ${finalScore}.`);\n }\n\n return traceLog;\n};\n\nexport function outcome(config, session, env) {\n return new Promise((resolve) => {\n const { value } = session || {};\n\n if (!session || !value) {\n resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true, logTrace: ['Student did not answer the question.'] });\n }\n\n if (value) {\n const { partA, partB } = value || {};\n\n const partialScoringEnabled = partialScoring.enabled(config, env);\n\n const scoreA = getScore(config, partA, 'partA', partialScoringEnabled);\n const scoreB = getScore(config, partB, 'partB', partialScoringEnabled);\n const logTrace = getLogTrace(config, session, env);\n\n if (!partialScoringEnabled) {\n // The EBSR item is worth 1 point\n // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded\n resolve({ score: scoreA === 1 && scoreB === 1 ? 1 : 0, scoreA, scoreB, max: 1, logTrace });\n } else {\n // The EBSR item is worth 2 points\n if (scoreA === 1) {\n if (scoreB === 1) {\n // If Part A and Part B are both correct, 2 points are awarded\n resolve({ score: 2, scoreA, scoreB, max: 2, logTrace });\n } else {\n // If Part A is correct and part B is incorrect, 1 point is awarded\n resolve({ score: 1, scoreA, scoreB, max: 2, logTrace });\n }\n } else {\n // For all other combinations, no points are awarded\n resolve({ score: 0, scoreA, scoreB, max: 2, logTrace });\n }\n }\n }\n });\n}\n\nconst returnPartCorrect = (choices) => {\n let answers = [];\n\n choices.forEach((i) => {\n const { correct, value } = i;\n if (correct) {\n answers.push(value);\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { partA, partB } = question;\n\n const partACorrect = returnPartCorrect(partA.choices);\n const partBCorrect = returnPartCorrect(partB.choices);\n\n resolve({\n value: {\n partA: {\n id: 'partA',\n value: partACorrect,\n },\n partB: {\n id: 'partB',\n value: partBCorrect,\n },\n },\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img, iframe and source tag for audio\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe|source)([^>]+)>)/gi, '');\n\nconst validatePart = (model = {}, config = {}) => {\n const { choices } = model;\n const { minAnswerChoices = 2, maxAnswerChoices } = config;\n const reversedChoices = [...(choices || [])].reverse();\n const errors = {};\n const choicesErrors = {};\n const rationaleErrors = {};\n let hasCorrectResponse = false;\n\n ['teacherInstructions', 'prompt'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n reversedChoices.forEach((choice, index) => {\n const { correct, value, label, rationale } = choice;\n\n if (correct) {\n hasCorrectResponse = true;\n }\n\n if (!getContent(label)) {\n choicesErrors[value] = 'Content should not be empty.';\n } else {\n const identicalAnswer = reversedChoices.slice(index + 1).some((c) => c.label === label);\n\n if (identicalAnswer) {\n choicesErrors[value] = 'Content should be unique.';\n }\n }\n\n if (config.rationale?.required && !getContent(rationale)) {\n rationaleErrors[value] = 'This field is required.';\n }\n });\n\n const nbOfChoices = (choices || []).length;\n\n if (nbOfChoices < minAnswerChoices) {\n errors.answerChoices = `There should be at least ${minAnswerChoices} choices defined.`;\n } else if (nbOfChoices > maxAnswerChoices) {\n errors.answerChoices = `No more than ${maxAnswerChoices} choices should be defined.`;\n }\n\n if (!hasCorrectResponse) {\n errors.correctResponse = 'No correct response defined.';\n }\n\n if (!isEmpty(choicesErrors)) {\n errors.choices = choicesErrors;\n }\n\n if (!isEmpty(rationaleErrors)) {\n errors.rationale = rationaleErrors;\n }\n\n return errors;\n};\n\nexport const validate = (model = {}, config = {}) => {\n const { partA, partB } = model || {};\n const { partA: partAConfig, partB: partBConfig } = config || {};\n\n const partAErrors = validatePart(partA, partAConfig);\n const partBErrors = validatePart(partB, partBConfig);\n\n return { partA: partAErrors, partB: partBErrors };\n};\n"],"mappings":"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","ignoreList":[]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pie-element/ebsr-controller",
3
3
  "private": true,
4
- "version": "10.1.1-next.1",
4
+ "version": "10.2.0-next.0",
5
5
  "description": "",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -312,7 +312,7 @@ describe('controller', () => {
312
312
  const returnsScoreWhen = (session) => {
313
313
  it(`returns empty: true if session is ${JSON.stringify(session)}`, async () => {
314
314
  const result = await outcome(question, session);
315
- expect(result).toEqual({ score: 0, scoreA: 0, scoreB: 0, empty: true });
315
+ expect(result).toEqual({ score: 0, scoreA: 0, scoreB: 0, empty: true, logTrace: ['Student did not answer the question.'] });
316
316
  });
317
317
  };
318
318
 
@@ -197,12 +197,101 @@ const getScore = (config, sessionPart, key, partialScoringEnabled) => {
197
197
  return parseFloat(maxScore ? (correctChoices / maxScore).toFixed(2) : 0);
198
198
  };
199
199
 
200
+ /**
201
+ * Generates detailed trace log for math-templated scoring evaluation
202
+ * @param {Object} question
203
+ * @param {Object} session
204
+ * @param {Object} env
205
+ * @returns {Array<string>} traceLog
206
+ */
207
+ export const getLogTrace = (question, session, env) => {
208
+ const traceLog = [];
209
+
210
+ if (!session || !session.value) {
211
+ traceLog.push('Student did not answer the question.');
212
+ return traceLog;
213
+ }
214
+
215
+ const { value } = session;
216
+ const { partA, partB } = value;
217
+
218
+ const partialScoringEnabled = partialScoring.enabled(question, env);
219
+
220
+ traceLog.push(
221
+ `Scoring method: ${partialScoringEnabled ? 'partial scoring' : 'all-or-nothing scoring'}.`
222
+ );
223
+
224
+ const partAquestionType =
225
+ question.partA.choiceMode === 'radio'
226
+ ? 'multiple-choice (radio)'
227
+ : 'multiple-select (checkbox)';
228
+ traceLog.push(`Part A question type: ${partAquestionType}.`);
229
+
230
+ const partASelections = partA?.value || [];
231
+ const partACorrectChoices = (question.partA.choices || []).filter((c) => c.correct);
232
+ const partACorrectValues = partACorrectChoices.map((c) => c.value);
233
+ const partACorrectSelected = partASelections.filter((v) => partACorrectValues.includes(v));
234
+ const partAIncorrectSelected = partASelections.filter((v) => !partACorrectValues.includes(v));
235
+
236
+ if (partASelections.length) {
237
+ traceLog.push(
238
+ `Part A: student selected ${partASelections.length} choice(s) (${partACorrectSelected.length} correct, ${partAIncorrectSelected.length} incorrect).`
239
+ );
240
+ }
241
+
242
+ const scoreA = getScore(question, partA, 'partA', partialScoringEnabled);
243
+ traceLog.push(`Part A score: ${scoreA}.`);
244
+
245
+ const partBquestionType =
246
+ question.partB.choiceMode === 'radio'
247
+ ? 'multiple-choice (radio)'
248
+ : 'multiple-select (checkbox)';
249
+ traceLog.push(`Part B question type: ${partBquestionType}.`);
250
+
251
+ const partBSelections = partB?.value || [];
252
+ const partBCorrectChoices = (question.partB.choices || []).filter((c) => c.correct);
253
+ const partBCorrectValues = partBCorrectChoices.map((c) => c.value);
254
+ const correctSelected = partBSelections.filter((v) => partBCorrectValues.includes(v));
255
+ const incorrectSelected = partBSelections.filter((v) => !partBCorrectValues.includes(v));
256
+
257
+ if (partBSelections.length) {
258
+ traceLog.push(
259
+ `Part B: student selected ${partBSelections.length} choice(s) (${correctSelected.length} correct, ${incorrectSelected.length} incorrect).`
260
+ );
261
+ }
262
+
263
+ const scoreB = getScore(question, partB, 'partB', partialScoringEnabled);
264
+ traceLog.push(`Part B score: ${scoreB}.`);
265
+
266
+ if (!partialScoringEnabled) {
267
+ traceLog.push(
268
+ 'Final score is awarded only if both Part A and Part B are completely correct.'
269
+ );
270
+ traceLog.push(`Final score: ${scoreA === 1 && scoreB === 1 ? 1 : 0}.`);
271
+ } else {
272
+ traceLog.push(
273
+ 'With partial scoring enabled, Part A must be correct to earn any credit.'
274
+ );
275
+
276
+ let finalScore = 0;
277
+ if (scoreA === 1 && scoreB === 1) {
278
+ finalScore = 2;
279
+ } else if (scoreA === 1 && scoreB < 1) {
280
+ finalScore = 1;
281
+ }
282
+
283
+ traceLog.push(`Final score: ${finalScore}.`);
284
+ }
285
+
286
+ return traceLog;
287
+ };
288
+
200
289
  export function outcome(config, session, env) {
201
290
  return new Promise((resolve) => {
202
291
  const { value } = session || {};
203
292
 
204
293
  if (!session || !value) {
205
- resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true });
294
+ resolve({ score: 0, scoreA: 0, scoreB: 0, empty: true, logTrace: ['Student did not answer the question.'] });
206
295
  }
207
296
 
208
297
  if (value) {
@@ -212,24 +301,25 @@ export function outcome(config, session, env) {
212
301
 
213
302
  const scoreA = getScore(config, partA, 'partA', partialScoringEnabled);
214
303
  const scoreB = getScore(config, partB, 'partB', partialScoringEnabled);
304
+ const logTrace = getLogTrace(config, session, env);
215
305
 
216
306
  if (!partialScoringEnabled) {
217
307
  // The EBSR item is worth 1 point
218
308
  // That point is awarded if and only if both parts are fully correct, otherwise no points are awarded
219
- resolve({ score: scoreA === 1 && scoreB === 1 ? 1 : 0, scoreA, scoreB, max: 1 });
309
+ resolve({ score: scoreA === 1 && scoreB === 1 ? 1 : 0, scoreA, scoreB, max: 1, logTrace });
220
310
  } else {
221
311
  // The EBSR item is worth 2 points
222
312
  if (scoreA === 1) {
223
313
  if (scoreB === 1) {
224
314
  // If Part A and Part B are both correct, 2 points are awarded
225
- resolve({ score: 2, scoreA, scoreB, max: 2 });
315
+ resolve({ score: 2, scoreA, scoreB, max: 2, logTrace });
226
316
  } else {
227
317
  // If Part A is correct and part B is incorrect, 1 point is awarded
228
- resolve({ score: 1, scoreA, scoreB, max: 2 });
318
+ resolve({ score: 1, scoreA, scoreB, max: 2, logTrace });
229
319
  }
230
320
  } else {
231
321
  // For all other combinations, no points are awarded
232
- resolve({ score: 0, scoreA, scoreB, max: 2 });
322
+ resolve({ score: 0, scoreA, scoreB, max: 2, logTrace });
233
323
  }
234
324
  }
235
325
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@pie-element/ebsr",
3
3
  "repository": "pie-framework/pie-elements",
4
- "version": "13.1.2-next.5",
4
+ "version": "13.2.0-next.0",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
9
  "dependencies": {
10
- "@pie-element/multiple-choice": "^12.1.2-next.5",
10
+ "@pie-element/multiple-choice": "^12.2.0-next.0",
11
11
  "@pie-framework/pie-player-events": "^0.1.0",
12
12
  "@pie-lib/translator": "3.2.0-next.3",
13
13
  "classnames": "^2.2.5",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "author": "pie framework developers",
18
18
  "license": "ISC",
19
- "gitHead": "a8b257ceb051bf973d80b1ae19138ae99117346b",
19
+ "gitHead": "11169f258ac462817f622c5272b360009b6675ab",
20
20
  "scripts": {
21
21
  "postpublish": "../../scripts/postpublish"
22
22
  },