@baravak/risloo-profile-cli 4.46.3 → 4.75.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.
Files changed (101) hide show
  1. package/.agents/skills/create-profile/SKILL.md +14 -0
  2. package/.claude/settings.local.json +1 -3
  3. package/.claude/skills/create-profile/SKILL.md +203 -0
  4. package/AGENTS.md +413 -0
  5. package/CLAUDE.md +2 -185
  6. package/package.json +1 -1
  7. package/src/cli-commands/Executor.js +8 -2
  8. package/src/cli-commands/ExtractExecutor.js +55 -21
  9. package/src/cli-commands/GiftExecutor.js +1 -0
  10. package/src/handlebars/importPartials.js +10 -44
  11. package/src/handlebars/init.js +17 -11
  12. package/src/publish/json/profiles/BSSI93.json +392 -0
  13. package/src/publish/json/profiles/FRHPT93.json +2 -2
  14. package/src/publish/json/profiles/ISKS93.json +288 -0
  15. package/src/publish/json/profiles/MCMI9A.json +1540 -0
  16. package/src/publish/json/profiles/NEO93.json +3858 -0
  17. package/src/publish/json/profiles/NEO9A.json +1159 -1
  18. package/src/publish/json/profiles/NEO9Q.json +3856 -0
  19. package/src/publish/json/profiles/NEO9V.json +1157 -0
  20. package/src/publish/json/profiles/RIASEC9A.json +2775 -0
  21. package/src/publish/json/profiles/RSI93.json +359 -0
  22. package/src/samples/AEQ93.js +1 -1
  23. package/src/samples/AMS93.js +1 -1
  24. package/src/samples/AMS9A.js +3 -1
  25. package/src/samples/BAOMEIS93.js +1 -1
  26. package/src/samples/BEQI93.js +1 -1
  27. package/src/samples/BSCT93.js +5 -0
  28. package/src/samples/BSSI93.js +93 -0
  29. package/src/samples/CAATS93.js +1 -1
  30. package/src/samples/CERQ93.js +1 -1
  31. package/src/samples/CRAAS93.js +1 -1
  32. package/src/samples/DSWLS93.js +1 -1
  33. package/src/samples/EMSS93.js +1 -1
  34. package/src/samples/EPQ9A.js +6 -1
  35. package/src/samples/FACES93.js +6 -0
  36. package/src/samples/FRHPT93.js +41 -13
  37. package/src/samples/GMIT93.js +1 -1
  38. package/src/samples/HPL93.js +1 -1
  39. package/src/samples/ISKS93.js +62 -0
  40. package/src/samples/IUS93.js +1 -1
  41. package/src/samples/JCSI93.js +1 -1
  42. package/src/samples/JPFQ93.js +5 -0
  43. package/src/samples/KJGI93.js +1 -1
  44. package/src/samples/LMIQ93.js +1 -1
  45. package/src/samples/MCMI9A.js +530 -0
  46. package/src/samples/MMFAD93.js +1 -1
  47. package/src/samples/MOCI93.js +1 -1
  48. package/src/samples/NEO93.js +279 -0
  49. package/src/samples/NEO9A.js +93 -60
  50. package/src/samples/NEO9Q.js +281 -0
  51. package/src/samples/NEO9V.js +218 -0
  52. package/src/samples/OBQ4493.js +1 -1
  53. package/src/samples/PIES93.js +1 -1
  54. package/src/samples/PIES9A.js +4 -0
  55. package/src/samples/PMCIEF93.js +7 -1
  56. package/src/samples/PSWQ93.js +1 -1
  57. package/src/samples/RIASEC93.js +1 -1
  58. package/src/samples/RIASEC9A.js +256 -0
  59. package/src/samples/RSI93.js +89 -0
  60. package/src/samples/SASQ93.js +1 -1
  61. package/src/samples/SDCAQ93.js +1 -1
  62. package/src/samples/STAIY93.js +1 -1
  63. package/src/samples/WAQ93.js +1 -1
  64. package/src/samples/YBOCS93.js +1 -1
  65. package/src/samples/YPI93.js +5 -1
  66. package/views/profiles/MCMI9A_facets_partial.hbs +96 -0
  67. package/views/profiles/MCMI9A_main_partial.hbs +262 -0
  68. package/views/profiles/MCMI9A_noteworthy_partial.hbs +66 -0
  69. package/views/profiles/MCMI9A_vertical_label_partial.hbs +8 -0
  70. package/views/profiles/NEO_long_facets.hbs +125 -0
  71. package/views/profiles/NEO_main.hbs +152 -0
  72. package/views/profiles/NEO_short_facets.hbs +82 -0
  73. package/views/profiles/samples/BSCT93.hbs +17 -17
  74. package/views/profiles/samples/BSSI93.hbs +102 -0
  75. package/views/profiles/samples/FRHPT93_1.hbs +568 -87
  76. package/views/profiles/samples/FRHPT93_2.hbs +90 -76
  77. package/views/profiles/samples/FRHPT93_3.hbs +2 -2
  78. package/views/profiles/samples/FRHPT93_4.hbs +2 -2
  79. package/views/profiles/samples/FRHPT93_5.hbs +103 -0
  80. package/views/profiles/samples/FRHPT9A.hbs +7 -7
  81. package/views/profiles/samples/ISKS93.hbs +38 -0
  82. package/views/profiles/samples/MCMI9A_1.hbs +3 -0
  83. package/views/profiles/samples/MCMI9A_2.hbs +3 -0
  84. package/views/profiles/samples/MCMI9A_3.hbs +3 -0
  85. package/views/profiles/samples/MCMI9A_4.hbs +3 -0
  86. package/views/profiles/samples/NEO93_1.hbs +14 -0
  87. package/views/profiles/samples/NEO93_2.hbs +15 -0
  88. package/views/profiles/samples/NEO93_3.hbs +15 -0
  89. package/views/profiles/samples/NEO9A.hbs +14 -29
  90. package/views/profiles/samples/NEO9Q_1.hbs +13 -0
  91. package/views/profiles/samples/NEO9Q_2.hbs +14 -0
  92. package/views/profiles/samples/NEO9Q_3.hbs +14 -0
  93. package/views/profiles/samples/NEO9V_1.hbs +13 -0
  94. package/views/profiles/samples/NEO9V_2.hbs +3 -0
  95. package/views/profiles/samples/RIASEC9A_1.hbs +38 -0
  96. package/views/profiles/samples/RIASEC9A_2.hbs +67 -0
  97. package/views/profiles/samples/RIASEC9A_3.hbs +93 -0
  98. package/views/profiles/samples/RSI93.hbs +101 -0
  99. package/a.json +0 -4805
  100. package/src/publish/json/profiles/BSCT93_t1.json +0 -512
  101. package/src/publish/json/profiles/BSCT93_t2.json +0 -512
@@ -0,0 +1,530 @@
1
+ const { Profile } = require("../Profile");
2
+
3
+ const INSIDE_THRESHOLD = 25;
4
+ const MAIN_INSIDE_SCORE_GAP = 2;
5
+ const FACET_INSIDE_SCORE_GAP = 6;
6
+ const OUTSIDE_SCORE_GAP = 6;
7
+
8
+ const PERSONALITY = [
9
+ { key: "1", code: "1", fa: "اسکیزوئید" },
10
+ { key: "2a", code: "2A", fa: "اجتنابی" },
11
+ { key: "2b", code: "2B", fa: "افسرده" },
12
+ { key: "3", code: "3", fa: "وابسته" },
13
+ { key: "4a", code: "4A", fa: "نمایشی" },
14
+ { key: "4b", code: "4B", fa: "آشفته" },
15
+ { key: "5", code: "5", fa: "خودشیفته" },
16
+ { key: "6a", code: "6A", fa: "ضداجتماعی" },
17
+ { key: "6b", code: "6B", fa: "دیگرآزار" },
18
+ { key: "7", code: "7", fa: "جبری" },
19
+ { key: "8a", code: "8A", fa: "منفی‌گرا" },
20
+ { key: "8b", code: "8B", fa: "خودآزار" },
21
+ { key: "s", code: "S", fa: "اسکیزوتایپال" },
22
+ { key: "c", code: "C", fa: "مرزی" },
23
+ { key: "p", code: "P", fa: "پارانوئید" },
24
+ ];
25
+
26
+ const CLINICAL = [
27
+ { key: "a", code: "A", fa: "اضطراب تعمیم‌یافته" },
28
+ { key: "h", code: "H", fa: "علائم جسمانی" },
29
+ { key: "n", code: "N", fa: "طیف دوقطبی" },
30
+ { key: "d", code: "D", fa: "افسردگی مداوم" },
31
+ { key: "b", code: "B", fa: "مصرف الکل" },
32
+ { key: "t", code: "T", fa: "مصرف مواد" },
33
+ { key: "r", code: "R", fa: "استرس پس از ضربه" },
34
+ { key: "ss", code: "SS", fa: "طیف اسکیزوفرنیا" },
35
+ { key: "cc", code: "CC", fa: "افسردگی اساسی" },
36
+ { key: "pp", code: "PP", fa: "اختلال هذیانی" },
37
+ ];
38
+
39
+ const MODIFYING = [
40
+ { key: "x", code: "X", fa: "افشا" },
41
+ { key: "y", code: "Y", fa: "مطلوبیت" },
42
+ { key: "z", code: "Z", fa: "منفی‌نمایی" },
43
+ ];
44
+
45
+ const FACET_NAMES = {
46
+ 1: ["غیرتعاملی", "از نظر درونی کم‌مایه", "از نظر خلق و خوی بی‌احساس"],
47
+ "2a": ["رویگردان از روابط بین‌فردی", "خودپنداره احساس عدم تعلق", "از نظر درونی آزرده"],
48
+ "2b": ["از نظر شناختی جبرگرا", "خود بی‌ارزش پنداری", "از نظر خلق ماتم‌زده"],
49
+ 3: ["نمودهای نابالغانه رفتاری", "از نظر بین‌فردی مطیع", "بی‌عرضه‌پنداری خود"],
50
+ "4a": ["به‌طور چشم‌گیری نمایشی", "از نظر بین‌فردی در جست‌وجوی توجه", "از نظر خلق ناپایدار"],
51
+ "4b": ["به وضوح تند و شتابزده", "از نظر بین‌فردی بی‌پروا", "خودبزرگ‌پنداری"],
52
+ 5: ["از نظر بین‌فردی استثمارگر", "از نظر ذهنی مهار نشده", "تصویری ستودنی از خود"],
53
+ "6a": ["مسئولیت‌ناپذیر در روابط اجتماعی", "خودمختار پنداری", "برون‌ریزی شدید"],
54
+ "6b": ["بیان تند و آزارنده", "کینه‌توز در روابط بین‌فردی", "منش انفجاری"],
55
+ 7: ["شدیداً منضبط", "از نظر شناختی خشک و ریزبین", "مطمئن به خود"],
56
+ "8a": ["بسیار تلخ و گزنده", "ناراضی از خود", "از نظر خلقی تحریک‌پذیر"],
57
+ "8b": ["خود نالایق‌پنداری", "منش متضاد (در تجربه لذت و درد)", "از نظر خلقی ملول"],
58
+ s: ["از نظر شناختی غیرعادی", "خودپنداره عجیب‌غریب", "از نظر درونی درهم"],
59
+ c: ["خودپنداره ناپایدار", "از نظر ساختار روانی دونیمه", "خلق بی‌ثبات"],
60
+ p: ["داشتن حالت تدافعی", "از نظر شناختی بی‌اعتماد", "فرافکنی مداوم"],
61
+ };
62
+
63
+ const NOTEWORTHY = [
64
+ { key: "ad", code: "AD", fa: "اختلال نقص‌توجه بیش‌فعالی بزرگسالان" },
65
+ { key: "as", code: "AS", fa: "طیف اتیسم" },
66
+ { key: "ca", code: "CA", fa: "سوءاستفاده کودکی" },
67
+ { key: "ea", code: "EA", fa: "اختلالات خوردن" },
68
+ { key: "em", code: "EM", fa: "عدم کنترل هیجانی" },
69
+ { key: "ex", code: "EX", fa: "خشم انفجاری" },
70
+ { key: "hp", code: "HP", fa: "دل‌مشغولی سلامتی" },
71
+ { key: "ia", code: "IA", fa: "بیگانگی با دیگران" },
72
+ { key: "pd", code: "PD", fa: "سوءمصرف داروهای تجویزی" },
73
+ { key: "sp", code: "SP", fa: "پتانسیل خود تخریبی" },
74
+ { key: "sb", code: "SB", fa: "رفتارها / تمایلات خودآسیبی" },
75
+ { key: "tb", code: "TB", fa: "آسیب تروماتیک مغز" },
76
+ { key: "vp", code: "VP", fa: "تمایل به انتقام جویی" },
77
+ ];
78
+
79
+ const THEMES = {
80
+ blue: {
81
+ gradient: "mcmBlue",
82
+ track: "#EFF6FF",
83
+ light: "#93C5FD",
84
+ dark: "#2563EB",
85
+ text: "#1E40AF",
86
+ cardText: "#1E40AF",
87
+ card: "#EFF6FF",
88
+ stroke: "#BFDBFE",
89
+ divider: "#DBEAFE",
90
+ },
91
+ gray: {
92
+ gradient: "mcmGray",
93
+ track: "#F8FAFC",
94
+ light: "#E2E8F0",
95
+ dark: "#475569",
96
+ text: "#475569",
97
+ cardText: "#475569",
98
+ card: "#F8FAFC",
99
+ stroke: "#E2E8F0",
100
+ divider: "#F1F5F9",
101
+ },
102
+ zinc: {
103
+ gradient: "mcmZinc",
104
+ track: "#FAFAFA",
105
+ dark: "#475569",
106
+ text: "#475569",
107
+ },
108
+ yellow: {
109
+ gradient: "mcmYellow",
110
+ track: "#FEFCE8",
111
+ light: "#FEF08A",
112
+ dark: "#EAB308",
113
+ text: "#EAB308",
114
+ cardText: "#EAB308",
115
+ card: "#FEFCE8",
116
+ stroke: "#FEF08A",
117
+ divider: "#FEF9C3",
118
+ },
119
+ orange: {
120
+ gradient: "mcmOrange",
121
+ track: "#FFF7ED",
122
+ light: "#FDBA74",
123
+ dark: "#EA580C",
124
+ text: "#EA580C",
125
+ cardText: "#EA580C",
126
+ card: "#FFF7ED",
127
+ stroke: "#FED7AA",
128
+ divider: "#FFEDD5",
129
+ },
130
+ rose: {
131
+ gradient: "mcmRose",
132
+ track: "#FFF1F2",
133
+ light: "#FDA4AF",
134
+ dark: "#E11D48",
135
+ text: "#E11D48",
136
+ cardText: "#BE123C",
137
+ card: "#FFF1F2",
138
+ stroke: "#FECDD3",
139
+ divider: "#FEE2E2",
140
+ },
141
+ };
142
+
143
+ const REPORTS = {
144
+ valid: {
145
+ text: "معتبر",
146
+ background: "#ECFDF5",
147
+ color: "#059669",
148
+ rawY: 54.2,
149
+ equalsY: 71,
150
+ reportY: 96.8,
151
+ },
152
+ questionable: {
153
+ text: "تفسیر با احتیاط",
154
+ background: "#FEFCE8",
155
+ color: "#CA8A04",
156
+ rawY: 27.1,
157
+ equalsY: 49.5,
158
+ reportY: 102,
159
+ },
160
+ invalid: {
161
+ text: "نامعتبر",
162
+ background: "#FEF2F2",
163
+ color: "#DC2626",
164
+ rawY: 50.9,
165
+ equalsY: 70,
166
+ reportY: 99.8,
167
+ },
168
+ };
169
+
170
+ const CORRECTIONS = {
171
+ none: {
172
+ text: "خیر",
173
+ background: "#FEF2F2",
174
+ color: "#DC2626",
175
+ bodyHeight: 68,
176
+ valid: false,
177
+ },
178
+ x: {
179
+ text: "شاخص افشا (X)",
180
+ background: "#ECFDF5",
181
+ color: "#059669",
182
+ bodyHeight: 131,
183
+ valid: true,
184
+ },
185
+ acc: {
186
+ text: "شاخص اضطراب/افسردگی (A/CC)",
187
+ background: "#ECFDF5",
188
+ color: "#059669",
189
+ bodyHeight: 211,
190
+ valid: true,
191
+ },
192
+ x_acc: {
193
+ text: "شاخص X و A/CC",
194
+ background: "#ECFDF5",
195
+ color: "#059669",
196
+ bodyHeight: 137,
197
+ valid: true,
198
+ },
199
+ };
200
+
201
+ const PROFILE_LABELS = {};
202
+ const addLabel = (eng) => {
203
+ PROFILE_LABELS[eng] = { eng };
204
+ };
205
+
206
+ for (const { key } of [...PERSONALITY, ...CLINICAL]) {
207
+ for (const suffix of ["raw", "br", "level"]) addLabel(`${key}_${suffix}`);
208
+ }
209
+ for (const key of Object.keys(FACET_NAMES)) {
210
+ for (let index = 1; index <= 3; index += 1) {
211
+ for (const suffix of ["raw", "br", "level"]) addLabel(`${key}_${index}_${suffix}`);
212
+ }
213
+ }
214
+ for (const { key } of MODIFYING) {
215
+ for (const suffix of ["raw", "br", "report", "level"]) addLabel(`${key}_${suffix}`);
216
+ }
217
+ for (const key of ["v", "w"]) {
218
+ addLabel(`${key}_raw`);
219
+ addLabel(`${key}_report`);
220
+ }
221
+ for (const eng of [
222
+ "high_point",
223
+ "validity_alert",
224
+ "validity_reason",
225
+ "correction_alert",
226
+ "correction_x_1",
227
+ "correction_x_2",
228
+ "correction_acc_value",
229
+ "correction_acc_1",
230
+ "correction_acc_2",
231
+ ]) {
232
+ addLabel(eng);
233
+ }
234
+ for (const { key } of NOTEWORTHY) {
235
+ addLabel(`noteworthy_${key}_raw`);
236
+ addLabel(`noteworthy_${key}_percentage`);
237
+ }
238
+
239
+ function clamp(value, min, max) {
240
+ const number = Number(value);
241
+ if (!Number.isFinite(number)) return min;
242
+ return Math.min(max, Math.max(min, number));
243
+ }
244
+
245
+ function brHeight(value) {
246
+ const br = clamp(value, 0, 115);
247
+ if (br <= 60) return br * 1.5;
248
+ if (br <= 75) return 90 + (br - 60) * 7;
249
+ if (br <= 85) return 195 + (br - 75) * 10;
250
+ return 295 + (br - 85) * 3.5;
251
+ }
252
+
253
+ function personalityTheme(value) {
254
+ const br = clamp(value, 0, 115);
255
+ if (br < 60) return THEMES.gray;
256
+ if (br < 75) return THEMES.yellow;
257
+ if (br < 85) return THEMES.orange;
258
+ return THEMES.rose;
259
+ }
260
+
261
+ function clinicalTheme(value) {
262
+ const br = clamp(value, 0, 115);
263
+ if (br < 75) return THEMES.gray;
264
+ if (br < 85) return THEMES.orange;
265
+ return THEMES.rose;
266
+ }
267
+
268
+ class MCMI9A extends Profile {
269
+ static pages = 4;
270
+
271
+ static partials = {
272
+ MCMI9A_main: "MCMI9A_main_partial.hbs",
273
+ MCMI9A_facets: "MCMI9A_facets_partial.hbs",
274
+ MCMI9A_noteworthy: "MCMI9A_noteworthy_partial.hbs",
275
+ MCMI9A_vertical_label: "MCMI9A_vertical_label_partial.hbs",
276
+ };
277
+
278
+ labels = PROFILE_LABELS;
279
+
280
+ profileSpec = {
281
+ sample: {
282
+ name: "آزمون شخصیت میلون IV",
283
+ multiProfile: false,
284
+ questions: false,
285
+ defaultFields: true,
286
+ fields: [],
287
+ },
288
+ profile: {
289
+ get dimensions() {
290
+ const [page1, page2, page3, page4] = this.padding;
291
+ return [
292
+ {
293
+ width: 888 + 2 * page1.x,
294
+ height: 706 + 2 * page1.y,
295
+ },
296
+ {
297
+ width: 858 + 2 * page2.x,
298
+ height: 699 + 2 * page2.y,
299
+ },
300
+ {
301
+ width: 858 + 2 * page3.x,
302
+ height: 699 + 2 * page3.y,
303
+ },
304
+ {
305
+ width: 737 + 2 * page4.x,
306
+ height: 558 + 2 * page4.y,
307
+ },
308
+ ];
309
+ },
310
+ padding: [
311
+ { x: 7.5, y: 4 },
312
+ { x: 22.5, y: 7.5 },
313
+ { x: 22.5, y: 7.5 },
314
+ { x: 83, y: 78 },
315
+ ],
316
+ },
317
+ labels: Object.values(this.labels),
318
+ };
319
+
320
+ constructor(dataset, options, config = {}) {
321
+ super();
322
+ this._init(dataset, options, config);
323
+ }
324
+
325
+ _calcContext() {
326
+ const scoreByKey = new Map(this.dataset.score.map((item) => [item.label.eng, item]));
327
+ const mark = (eng) => scoreByKey.get(eng)?.mark ?? 0;
328
+ const number = (eng) => {
329
+ const value = Number(mark(eng));
330
+ return Number.isFinite(value) ? value : 0;
331
+ };
332
+ const titleAppend = (page) => ` - صفحه ${page}`;
333
+
334
+ const modifying = MODIFYING.map((item, index) => {
335
+ const br = clamp(number(`${item.key}_br`), 0, 100);
336
+ const barHeight = br * 4;
337
+ const inside = br >= INSIDE_THRESHOLD;
338
+ const barTop = 464 - barHeight;
339
+ return {
340
+ ...item,
341
+ x: 144 + index * 20,
342
+ center: 150 + index * 20,
343
+ raw: number(`${item.key}_raw`),
344
+ br,
345
+ barHeight,
346
+ barTop,
347
+ scoreY: inside ? barTop + MAIN_INSIDE_SCORE_GAP : barTop - OUTSIDE_SCORE_GAP,
348
+ scoreAnchor: inside ? "end" : "start",
349
+ inside,
350
+ theme: THEMES.blue,
351
+ };
352
+ });
353
+
354
+ const personality = PERSONALITY.map((item, index) => {
355
+ const br = clamp(number(`${item.key}_br`), 0, 115);
356
+ const barHeight = brHeight(br);
357
+ const x = index < 12 ? 276 + index * 20 : 532 + (index - 12) * 20;
358
+ const inside = br >= 60;
359
+ const barTop = 464 - barHeight;
360
+ return {
361
+ ...item,
362
+ x,
363
+ center: x + 6,
364
+ raw: number(`${item.key}_raw`),
365
+ br,
366
+ level: mark(`${item.key}_level`),
367
+ barHeight,
368
+ barTop,
369
+ scoreY: inside ? barTop + MAIN_INSIDE_SCORE_GAP : barTop - OUTSIDE_SCORE_GAP,
370
+ scoreAnchor: inside ? "end" : "start",
371
+ inside,
372
+ theme: personalityTheme(br),
373
+ };
374
+ });
375
+
376
+ const clinical = CLINICAL.map((item, index) => {
377
+ const br = clamp(number(`${item.key}_br`), 0, 115);
378
+ const barHeight = brHeight(br);
379
+ const x = index < 7 ? 672 + index * 20 : 828 + (index - 7) * 20;
380
+ const inside = br >= 75;
381
+ const barTop = 464 - barHeight;
382
+ return {
383
+ ...item,
384
+ x,
385
+ center: x + 6,
386
+ raw: number(`${item.key}_raw`),
387
+ br,
388
+ level: mark(`${item.key}_level`),
389
+ barHeight,
390
+ barTop,
391
+ scoreY: inside ? barTop + MAIN_INSIDE_SCORE_GAP : barTop - OUTSIDE_SCORE_GAP,
392
+ scoreAnchor: inside ? "end" : "start",
393
+ inside,
394
+ theme: clinicalTheme(br),
395
+ };
396
+ });
397
+
398
+ const facetGroups = (order, forcedGrayKeys) =>
399
+ order.map((key, groupIndex) => {
400
+ const parent = PERSONALITY.find((item) => item.key === key);
401
+ const br = clamp(number(`${key}_br`), 0, 115);
402
+ const forcedGray = forcedGrayKeys.has(key);
403
+ const theme = forcedGray ? THEMES.gray : personalityTheme(br);
404
+ const baseX = 42 + groupIndex * 104;
405
+ const facets = FACET_NAMES[key].map((fa, facetIndex) => {
406
+ const facetKey = `${key}_${facetIndex + 1}`;
407
+ const facetBr = clamp(number(`${facetKey}_br`), 0, 100);
408
+ const barHeight = facetBr * 3;
409
+ const inside = facetBr >= 75;
410
+ const facetTheme = forcedGray
411
+ ? THEMES.gray
412
+ : inside
413
+ ? theme
414
+ : THEMES.zinc;
415
+ const barTop = 361 - barHeight;
416
+ return {
417
+ key: facetKey,
418
+ code: `${parent.code}-${facetIndex + 1}`,
419
+ fa,
420
+ x: baseX + facetIndex * 28,
421
+ center: baseX + facetIndex * 28 + 8,
422
+ raw: number(`${facetKey}_raw`),
423
+ br: facetBr,
424
+ level: mark(`${facetKey}_level`),
425
+ barHeight,
426
+ barTop,
427
+ scoreY: inside ? barTop + FACET_INSIDE_SCORE_GAP : barTop - OUTSIDE_SCORE_GAP,
428
+ scoreAnchor: inside ? "end" : "start",
429
+ inside,
430
+ theme: facetTheme,
431
+ };
432
+ });
433
+
434
+ return {
435
+ ...parent,
436
+ cardLines: key === "6b" ? ["دیگرآزار", "(سادیستیک)"] : [parent.fa],
437
+ baseX,
438
+ cardX: baseX - 3.5,
439
+ raw: number(`${key}_raw`),
440
+ br,
441
+ level: mark(`${key}_level`),
442
+ theme,
443
+ facets,
444
+ };
445
+ });
446
+
447
+ const sortedFacetKeys = PERSONALITY.map((item, index) => ({
448
+ key: item.key,
449
+ index,
450
+ br: clamp(number(`${item.key}_br`), 0, 115),
451
+ }))
452
+ .sort((first, second) => second.br - first.br || first.index - second.index)
453
+ .map((item) => item.key);
454
+ const forcedGrayKeys = new Set(sortedFacetKeys.slice(-4));
455
+
456
+ const noteworthy = NOTEWORTHY.map((item, index) => {
457
+ const raw = number(`noteworthy_${item.key}_raw`);
458
+ const ratio = clamp(number(`noteworthy_${item.key}_percentage`), 0, 1);
459
+ const percentage = Math.round(ratio * 100);
460
+ const barWidth = percentage * 4;
461
+ return {
462
+ ...item,
463
+ index,
464
+ rowY: 30 + index * 40,
465
+ barY: 42 + index * 40,
466
+ centerY: 50 + index * 40,
467
+ raw,
468
+ ratio,
469
+ percentage,
470
+ barWidth,
471
+ inside: percentage >= INSIDE_THRESHOLD,
472
+ scoreX: 273 + barWidth + (percentage >= INSIDE_THRESHOLD ? -6 : 6),
473
+ };
474
+ });
475
+
476
+ const correctionKey = String(mark("correction_alert") || "none");
477
+ const correction = CORRECTIONS[correctionKey] ?? CORRECTIONS.none;
478
+ const validity = (key) => {
479
+ const reportKey = String(mark(`${key}_report`) || "valid");
480
+ return {
481
+ raw: number(`${key}_raw`),
482
+ ...(REPORTS[reportKey] ?? REPORTS.valid),
483
+ };
484
+ };
485
+ const highPoints = [...personality, ...clinical]
486
+ .map((item, index) => ({ ...item, highPointOrder: index }))
487
+ .filter((item) => item.br >= 75)
488
+ .sort(
489
+ (first, second) =>
490
+ second.br - first.br || first.highPointOrder - second.highPointOrder,
491
+ )
492
+ .map((item) => item.code)
493
+ .slice(0, 5);
494
+ const disclosureRaw = number("x_raw");
495
+ const showDisclosureAlert =
496
+ disclosureRaw <= 6 || (disclosureRaw >= 115 && disclosureRaw <= 121);
497
+
498
+ return [
499
+ {
500
+ page: 1,
501
+ titleAppend: titleAppend(1),
502
+ highPoints,
503
+ showDisclosureAlert,
504
+ correction,
505
+ validityV: validity("v"),
506
+ validityW: validity("w"),
507
+ modifying,
508
+ personality,
509
+ clinical,
510
+ },
511
+ {
512
+ page: 2,
513
+ titleAppend: titleAppend(2) + ' - گراسمن ۱',
514
+ groups: facetGroups(sortedFacetKeys.slice(0, 8), forcedGrayKeys),
515
+ },
516
+ {
517
+ page: 3,
518
+ titleAppend: titleAppend(3)+ ' - گراسمن ۲',
519
+ groups: facetGroups(sortedFacetKeys.slice(8), forcedGrayKeys),
520
+ },
521
+ {
522
+ page: 4,
523
+ titleAppend: titleAppend(4) + ' - شاخص‌های هشداردهنده',
524
+ items: noteworthy,
525
+ },
526
+ ];
527
+ }
528
+ }
529
+
530
+ module.exports = MCMI9A;
@@ -25,7 +25,7 @@ class MMAFD93 extends Profile {
25
25
  multiProfile: false /* Whether the sample has multiple profiles or not */,
26
26
  questions: false /* Determines whether to get questions from inital dataset or not */,
27
27
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
28
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
28
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
29
29
  },
30
30
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
31
31
  /* calculating its dimensions carefully is of great importance */
@@ -22,7 +22,7 @@ class MOCI93 extends Profile {
22
22
  multiProfile: false /* Whether the sample has multiple profiles or not */,
23
23
  questions: false /* Determines whether to get questions from inital dataset or not */,
24
24
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
25
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
25
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
26
26
  },
27
27
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
28
28
  /* calculating its dimensions carefully is of great importance */