@baravak/risloo-profile-cli 4.46.2 → 4.70.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 (90) hide show
  1. package/.agents/skills/create-profile/SKILL.md +14 -0
  2. package/.claude/settings.local.json +7 -0
  3. package/.claude/skills/create-profile/SKILL.md +80 -0
  4. package/AGENTS.md +239 -0
  5. package/CLAUDE.md +5 -0
  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/BSCT93.json +495 -0
  13. package/src/publish/json/profiles/BSSI93.json +392 -0
  14. package/src/publish/json/profiles/FRHPT93.json +2 -2
  15. package/src/publish/json/profiles/ISKS93.json +288 -0
  16. package/src/publish/json/profiles/MCMI9A.json +1540 -0
  17. package/src/publish/json/profiles/NEO93.json +3858 -0
  18. package/src/publish/json/profiles/NEO9A.json +1159 -1
  19. package/src/publish/json/profiles/NEO9Q.json +3856 -0
  20. package/src/publish/json/profiles/NEO9V.json +1157 -0
  21. package/src/publish/json/profiles/RIASEC9A.json +2775 -0
  22. package/src/publish/json/profiles/RSI93.json +359 -0
  23. package/src/samples/AEQ93.js +1 -1
  24. package/src/samples/AMS93.js +1 -1
  25. package/src/samples/AMS9A.js +3 -1
  26. package/src/samples/BAOMEIS93.js +1 -1
  27. package/src/samples/BEQI93.js +1 -1
  28. package/src/samples/BSCT93.js +90 -0
  29. package/src/samples/BSSI93.js +93 -0
  30. package/src/samples/CAATS93.js +1 -1
  31. package/src/samples/CERQ93.js +1 -1
  32. package/src/samples/CRAAS93.js +1 -1
  33. package/src/samples/DSWLS93.js +1 -1
  34. package/src/samples/EMSS93.js +1 -1
  35. package/src/samples/EPQ9A.js +6 -1
  36. package/src/samples/FACES93.js +6 -0
  37. package/src/samples/FRHPT93.js +41 -13
  38. package/src/samples/GMIT93.js +1 -1
  39. package/src/samples/HPL93.js +1 -1
  40. package/src/samples/ISKS93.js +62 -0
  41. package/src/samples/IUS93.js +1 -1
  42. package/src/samples/JCSI93.js +1 -1
  43. package/src/samples/JPFQ93.js +5 -0
  44. package/src/samples/KJGI93.js +1 -1
  45. package/src/samples/LMIQ93.js +1 -1
  46. package/src/samples/MMFAD93.js +1 -1
  47. package/src/samples/MOCI93.js +1 -1
  48. package/src/samples/NEO93.js +277 -0
  49. package/src/samples/NEO9A.js +91 -60
  50. package/src/samples/NEO9Q.js +279 -0
  51. package/src/samples/NEO9V.js +215 -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/NEO_long_facets.hbs +125 -0
  67. package/views/profiles/NEO_main.hbs +150 -0
  68. package/views/profiles/NEO_short_facets.hbs +82 -0
  69. package/views/profiles/samples/BSCT93.hbs +99 -0
  70. package/views/profiles/samples/BSSI93.hbs +102 -0
  71. package/views/profiles/samples/FRHPT93_1.hbs +570 -87
  72. package/views/profiles/samples/FRHPT93_2.hbs +90 -76
  73. package/views/profiles/samples/FRHPT93_3.hbs +2 -2
  74. package/views/profiles/samples/FRHPT93_4.hbs +2 -2
  75. package/views/profiles/samples/FRHPT93_5.hbs +103 -0
  76. package/views/profiles/samples/FRHPT9A.hbs +7 -7
  77. package/views/profiles/samples/ISKS93.hbs +38 -0
  78. package/views/profiles/samples/NEO93_1.hbs +14 -0
  79. package/views/profiles/samples/NEO93_2.hbs +15 -0
  80. package/views/profiles/samples/NEO93_3.hbs +15 -0
  81. package/views/profiles/samples/NEO9A.hbs +14 -29
  82. package/views/profiles/samples/NEO9Q_1.hbs +13 -0
  83. package/views/profiles/samples/NEO9Q_2.hbs +14 -0
  84. package/views/profiles/samples/NEO9Q_3.hbs +14 -0
  85. package/views/profiles/samples/NEO9V_1.hbs +13 -0
  86. package/views/profiles/samples/NEO9V_2.hbs +3 -0
  87. package/views/profiles/samples/RIASEC9A_1.hbs +38 -0
  88. package/views/profiles/samples/RIASEC9A_2.hbs +67 -0
  89. package/views/profiles/samples/RIASEC9A_3.hbs +93 -0
  90. package/views/profiles/samples/RSI93.hbs +101 -0
@@ -24,6 +24,10 @@ const customConfig = {
24
24
  // This profile is partially identical to PIES93
25
25
 
26
26
  class PIES9A extends PIES93 {
27
+ static partials = {
28
+ PIES93: "samples/PIES93.hbs",
29
+ };
30
+
27
31
  constructor(dataset, options, config = customConfig) {
28
32
  super(dataset, options, config);
29
33
  }
@@ -1,12 +1,18 @@
1
1
  const { Profile, FS } = require("../Profile");
2
2
  const JPFQ93 = require("./JPFQ93");
3
3
  const FACES93 = require("./FACES93");
4
- const Handlebars = require("handlebars");
5
4
 
6
5
  class PMCIEF93 extends Profile {
7
6
  // Number of pages
8
7
  static pages = 1;
9
8
 
9
+ static partials = {
10
+ JPFQ93_partial: "samples/JPFQ93_partial.hbs",
11
+ FACES93_1_partial: "samples/FACES93_1_partial.hbs",
12
+ FACES93_2_1_partial: "samples/FACES93_2_1_partial.hbs",
13
+ FACES93_2_2_partial: "samples/FACES93_2_2_partial.hbs",
14
+ };
15
+
10
16
  // Labels of the sample
11
17
  labels = {
12
18
  L1 : {"eng" : "axis_2_raw", "fr" : ""},
@@ -19,7 +19,7 @@ class PSWQ93 extends Profile {
19
19
  multiProfile: false /* Whether the sample has multiple profiles or not */,
20
20
  questions: false /* Determines whether to get questions from inital dataset or not */,
21
21
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
22
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
22
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
23
23
  },
24
24
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
25
25
  /* calculating its dimensions carefully is of great importance */
@@ -23,7 +23,7 @@ class RIASEC93 extends Profile {
23
23
  multiProfile: false /* Whether the sample has multiple profiles or not */,
24
24
  questions: true /* Determines whether to get questions from inital dataset or not */,
25
25
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
26
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
26
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
27
27
  },
28
28
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
29
29
  /* calculating its dimensions carefully is of great importance */
@@ -0,0 +1,256 @@
1
+ const { Profile, Mappings } = require("../Profile");
2
+
3
+ class RIASEC9A extends Profile {
4
+ // Number of pages
5
+ static pages = 3;
6
+
7
+ // Labels of the sample
8
+ labels = {
9
+ L1_0: { eng: "realistic_raw", fr: "واقع‌گرا", short: "و", enShort:"R" },
10
+ L1_1: { eng: "realistic_percentage" },
11
+ L1_2: { eng: "realistic_rank" },
12
+ L1_3: { eng: "realistic_congruence" },
13
+ L1_4: { eng: "realistic_calibrated" },
14
+ L2_0: { eng: "investigative_raw", fr: "جستجوگر", short: "ج", enShort:"I" },
15
+ L2_1: { eng: "investigative_percentage" },
16
+ L2_2: { eng: "investigative_rank" },
17
+ L2_3: { eng: "investigative_congruence" },
18
+ L2_4: { eng: "investigative_calibrated" },
19
+ L3_0: { eng: "artistic_raw", fr: "هنری", short: "هـ", enShort:"A" },
20
+ L3_1: { eng: "artistic_percentage" },
21
+ L3_2: { eng: "artistic_rank" },
22
+ L3_3: { eng: "artistic_congruence" },
23
+ L3_4: { eng: "artistic_calibrated" },
24
+ L4_0: { eng: "social_raw", fr: "اجتماعی", short: "الف", enShort:"S" },
25
+ L4_1: { eng: "social_percentage" },
26
+ L4_2: { eng: "social_rank" },
27
+ L4_3: { eng: "social_congruence" },
28
+ L4_4: { eng: "social_calibrated" },
29
+ L5_0: { eng: "enterprising_raw", fr: "متهور", short: "م", enShort:"E" },
30
+ L5_1: { eng: "enterprising_percentage" },
31
+ L5_2: { eng: "enterprising_rank" },
32
+ L5_3: { eng: "enterprising_congruence" },
33
+ L5_4: { eng: "enterprising_calibrated" },
34
+ L6_0: { eng: "conventional_raw", fr: "قراردادی", short: "ق", enShort:"C" },
35
+ L6_1: { eng: "conventional_percentage" },
36
+ L6_2: { eng: "conventional_rank" },
37
+ L6_3: { eng: "conventional_congruence" },
38
+ L6_4: { eng: "conventional_calibrated" },
39
+ Llt: { eng: "code_letters_abbr" },
40
+
41
+ };
42
+
43
+ profileSpec = {
44
+ /* "sample" determines some important info about the sample and profile */
45
+ /* Default prerequisites: 1. gender, 2. age, 3. education */
46
+ /* "prerequisites" is synonym to "fields" in our program */
47
+ sample: {
48
+ name: "پرسشنامه رغبت‌سنج تحصیلی - شغلی هالند - ویرایش حوزه" /* Name of the sample */,
49
+ multiProfile: false /* Whether the sample has multiple profiles or not */,
50
+ questions: true /* Determines whether to get questions from inital dataset or not */,
51
+ defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
52
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
53
+ },
54
+ /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
55
+ /* calculating its dimensions carefully is of great importance */
56
+ profile: {
57
+ get dimensions() {
58
+ return [
59
+ {
60
+ width: 602 + 2 * this.padding[0].x,
61
+ height: 595 + 2 * this.padding[0].y,
62
+ },
63
+ {
64
+ width: 592 + 2 * this.padding[1].x,
65
+ height: 523 + 2 * this.padding[1].y,
66
+ },
67
+ {
68
+ width: 686 + 2 * this.padding[2].x,
69
+ height: 404 + 2 * this.padding[2].y,
70
+ },
71
+ ];
72
+ },
73
+ padding: [
74
+ {
75
+ x: 0,
76
+ y: 51,
77
+ },
78
+ {
79
+ x: 147,
80
+ y: 96,
81
+ },
82
+ {
83
+ x: 109,
84
+ y: 155,
85
+ },
86
+ ],
87
+ },
88
+ /* "items" is the general term used for independent data elements to be drawn in the profile */
89
+ items: {
90
+ offsetY: 32 /* Horizontal offset between two top items */,
91
+ get distanceY() {
92
+ return this.offsetY + this.rect.body.height;
93
+ } /* Horizontal distance between two top items */,
94
+ maxValue: 50 /* Maximum value of items */,
95
+ rect: {
96
+ base: {
97
+ height: 4,
98
+ },
99
+ body: {
100
+ height: 8,
101
+ brs: {
102
+ tl: 0,
103
+ tr: 4,
104
+ bl: 0,
105
+ br: 0,
106
+ },
107
+ },
108
+ widthCoeff: 500 / 56,
109
+ opacityMappings: new Mappings()
110
+ .addMapping("1-10", 0.6)
111
+ .addMapping("11-20", 0.7)
112
+ .addMapping("21-30", 0.8)
113
+ .addMapping("31-40", 0.9)
114
+ .addMapping("41-50", 1) /* Opacity mapping for marks */,
115
+ },
116
+ },
117
+ /* "labels" part which has to be provided for each profile */
118
+ labels: Object.values(this.labels),
119
+ };
120
+
121
+ constructor(dataset, options, config = {}) {
122
+ super();
123
+ this._init(dataset, options, config);
124
+ }
125
+
126
+ _calcContext() {
127
+ const {
128
+ spec: { parameters: spec },
129
+ dataset,
130
+ } = this;
131
+
132
+ // Deconstructing the Spec of the Profile
133
+ const { items: itemsSpec } = spec;
134
+ const Items = [];
135
+ for (let i = 0; i < 30; i += 5) {
136
+ const item = dataset.score[i];
137
+ item.percentage = dataset.score[i + 1].mark ?? 0;
138
+ item.rank = dataset.score[i + 2].mark ?? 0;
139
+ item.congruence = dataset.score[i + 3].mark ?? 0;
140
+ item.calibrated = dataset.score[i + 4].mark ?? 0;
141
+ Items.push(item);
142
+ }
143
+ const map = new Map(Items.map(i => [i.label.enShort, i.label.short]))
144
+ const reportMap = dataset.score[30].mark.split('-').map(r => {
145
+ return r.split(',').map(key => map.get(key)).join(' - ')
146
+ }).reverse()
147
+ // Gathering required info for page 1 items
148
+ const items = Items.map((data) => ({
149
+ label: data.label,
150
+ mark: data.mark,
151
+ width: data.mark * itemsSpec.rect.widthCoeff,
152
+ opacity: itemsSpec.rect.opacityMappings.map(data.mark),
153
+ percentage: data.percentage,
154
+ rank: data.rank,
155
+ congruence: data.congruence,
156
+ calibrated: data.calibrated,
157
+ }));
158
+ const questionItems = [
159
+ {
160
+ label: "فعالیت‌ها",
161
+ marks: Array(6)
162
+ .fill(11)
163
+ .map((n, index) =>
164
+ dataset.questions
165
+ .slice(index * n, (index + 1) * n)
166
+ .reduce((sum, { user_answered }) => sum + (+user_answered !== 2 ? 1 : 0), 0)
167
+ ),
168
+ },
169
+ {
170
+ label: "تجربه‌ها",
171
+ marks: Array(6)
172
+ .fill(11)
173
+ .map((n, index) =>
174
+ dataset.questions
175
+ .slice(66 + index * n, 66 + (index + 1) * n)
176
+ .reduce((sum, { user_answered }) => sum + (+user_answered !== 2 ? 1 : 0), 0)
177
+ ),
178
+ },
179
+ {
180
+ label: "مشاغل",
181
+ marks: Array(6)
182
+ .fill(14)
183
+ .map((n, index) =>
184
+ dataset.questions
185
+ .slice(132 + index * n, 132 + (index + 1) * n)
186
+ .reduce((sum, { user_answered }) => sum + (+user_answered !== 2 ? 1 : 0), 0)
187
+ ),
188
+ },
189
+ {
190
+ label: "خودسنجی ۱",
191
+ marks: dataset.questions.slice(216, 216 + 6).map((q) => +q.user_answered),
192
+ },
193
+ {
194
+ label: "خودسنجی ۲",
195
+ marks: dataset.questions.slice(222, 222 + 6).map((q) => +q.user_answered),
196
+ },
197
+ ];
198
+ const itemObject = {};
199
+ let last = undefined;
200
+ const list = items
201
+ .map((item) => item.mark)
202
+ .sort((a, b) => b - a)
203
+ .filter((mark, i) => {
204
+ if (i <= 2) {
205
+ last = mark;
206
+ return true;
207
+ }
208
+ if (mark === last) {
209
+ return true;
210
+ } else {
211
+ return false;
212
+ }
213
+ });
214
+ items.forEach((item) => (itemObject[item.label.eng.slice(0, -4)] = item));
215
+ const itemRadians = [
216
+ itemObject.artistic,
217
+ itemObject.social,
218
+ itemObject.enterprising,
219
+ itemObject.conventional,
220
+ itemObject.realistic,
221
+ itemObject.investigative,
222
+ ].map((item, i) => {
223
+ const mark = ((item.mark ?? 0) * 207) / 56;
224
+ item.rad = pointsToCoordinates(mark - 14, i * 60);
225
+ item.bold = list.includes(item.mark);
226
+ item.percentageText = Math.floor(item.percentage * 100);
227
+ return item;
228
+ });
229
+ return [
230
+ {
231
+ items: [...items].sort((item1, item2) => item2.mark - item1.mark),
232
+ questionItems,
233
+ titleAppend: " - ۱",
234
+ },
235
+ {
236
+ itemRadians,
237
+ titleAppend: " - ۲",
238
+ },
239
+ {
240
+ items: [...items].reverse(),
241
+ reportMap,
242
+ titleAppend: " - ۳",
243
+ },
244
+ ];
245
+ }
246
+ }
247
+
248
+ function pointsToCoordinates(mark, angle) {
249
+ angle = (angle * Math.PI) / 180;
250
+ const start = [296 + 31 * Math.cos(angle), 261.5 + 31 * Math.sin(angle)];
251
+ const end = [start[0] + mark * Math.cos(angle), start[1] + mark * Math.sin(angle)];
252
+ const value = [end[0] + 12 * Math.cos(angle), end[1] + 12 * Math.sin(angle)];
253
+ return { start, end, value };
254
+ }
255
+
256
+ module.exports = RIASEC9A;
@@ -0,0 +1,89 @@
1
+ const { Profile } = require("../Profile");
2
+
3
+ class RSI93 extends Profile {
4
+ static pages = 1;
5
+
6
+ // RSI93 — "تصور از خدا" (خسروی). Chart has two halves:
7
+ // • Left : two mirrored donut-ring gauges (pink = negative image, green = positive image).
8
+ // • Right : two horizontal bars (god_in_life, god_cares) — the two sub-factors whose
9
+ // sum is the positive-image score (per the designer).
10
+ // Maxes = items × 5 (scoring/RSI93.py → round(raw / (count·5), 2)):
11
+ // negative_image 6→30, positive_image 21→105, god_in_life 11→55, god_cares 10→50.
12
+ // Each factor exposes _raw + _percentage; we read raw for the "X از Y" fraction and the
13
+ // 0–1 percentage for the fill sweep + the "٪ NN" label (designer: "محاسبه با درصد").
14
+ labels = {
15
+ L1_1: { eng: "negative_image_raw", max: 30 },
16
+ L1_2: { eng: "negative_image_percentage" },
17
+
18
+ L2_1: { eng: "positive_image_raw", max: 105 },
19
+ L2_2: { eng: "positive_image_percentage" },
20
+
21
+ L3_1: { eng: "god_in_life_raw", max: 55, title: "حضور خدا در زندگی" },
22
+ L3_2: { eng: "god_in_life_percentage" },
23
+
24
+ L4_1: { eng: "god_cares_raw", max: 50, title: "مراقبت خداوند" },
25
+ L4_2: { eng: "god_cares_percentage" },
26
+ };
27
+
28
+ profileSpec = {
29
+ sample: {
30
+ name: "پرسشنامه تصور از خدا (خسروی)",
31
+ multiProfile: false,
32
+ questions: false,
33
+ defaultFields: true,
34
+ fields: [],
35
+ },
36
+ profile: {
37
+ get dimensions() {
38
+ return {
39
+ width: 740 + 2 * this.padding.x, // Chart layer 740 wide → 943 page
40
+ height: 318 + 2 * this.padding.y, // Chart layer 318 tall → 754 page
41
+ };
42
+ },
43
+ padding: {
44
+ x: 101.5, // (943 − 740) / 2
45
+ y: 218, // (754 − 318) / 2
46
+ },
47
+ },
48
+ labels: Object.values(this.labels),
49
+ };
50
+
51
+ constructor(dataset, options, config = {}) {
52
+ super();
53
+ this._init(dataset, options, config);
54
+ }
55
+
56
+ _calcContext() {
57
+ const { dataset } = this;
58
+ const s = dataset.score;
59
+
60
+ const neg = packItem(s[0], s[1]); // negative image → left ring (pink)
61
+ const pos = packItem(s[2], s[3]); // positive image → right ring (green)
62
+
63
+ // Ring fill sweep. Both rings: 0 % at the bottom base (90°), 100 % at the top.
64
+ // • Left ring fills clockwise up the LEFT (increasing θ): zeta = π/2 + p·π (direction false).
65
+ // • Right ring fills counter-cw up the RIGHT (decreasing θ): zeta = π/2 − p·π (direction true).
66
+ neg.zeta = Math.PI / 2 + neg.p * Math.PI;
67
+ pos.zeta = Math.PI / 2 - pos.p * Math.PI;
68
+
69
+ const bars = [
70
+ packItem(s[4], s[5]), // god_in_life
71
+ packItem(s[6], s[7]), // god_cares
72
+ ];
73
+
74
+ return [{ neg, pos, bars }];
75
+ }
76
+ }
77
+
78
+ // Merge a factor's _raw and _percentage score entries into one drawing item.
79
+ function packItem(raw, percentage) {
80
+ return {
81
+ label: raw.label,
82
+ max: raw.label.max,
83
+ mark: raw.mark ?? 0,
84
+ percentage: Math.round((percentage.mark ?? 0) * 100),
85
+ p: percentage.mark ?? 0,
86
+ };
87
+ }
88
+
89
+ module.exports = RSI93;
@@ -19,7 +19,7 @@ class SASQ93 extends Profile {
19
19
  multiProfile: false /* Whether the sample has multiple profiles or not */,
20
20
  questions: false /* Determines whether to get questions from inital dataset or not */,
21
21
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
22
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
22
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
23
23
  },
24
24
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
25
25
  /* calculating its dimensions carefully is of great importance */
@@ -23,7 +23,7 @@ class SDCAQ93 extends Profile {
23
23
  multiProfile: false /* Whether the sample has multiple profiles or not */,
24
24
  questions: false /* Determines whether to get questions from inital dataset or not */,
25
25
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
26
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
26
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
27
27
  },
28
28
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
29
29
  /* calculating its dimensions carefully is of great importance */
@@ -19,7 +19,7 @@ class STAIY93 extends Profile {
19
19
  multiProfile: false /* Whether the sample has multiple profiles or not */,
20
20
  questions: false /* Determines whether to get questions from inital dataset or not */,
21
21
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
22
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
22
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
23
23
  },
24
24
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
25
25
  /* calculating its dimensions carefully is of great importance */
@@ -25,7 +25,7 @@ class WAQ93 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 */
@@ -398,7 +398,7 @@ class YBOCS93 extends Profile {
398
398
  multiProfile: true /* Whether the sample has multiple profiles or not */,
399
399
  questions: true /* Determines whether to get questions from inital dataset or not */,
400
400
  defaultFields: true /* Determines whether to have default prerequisites in the profile or not */,
401
- fields: ["marital_status"] /* In case you want to get some additional fields and show in the profile */,
401
+ fields: [] /* In case you want to get some additional fields and show in the profile */,
402
402
  },
403
403
  /* "profile" determines the dimensions of the drawn profile (to be used in svg tag viewbox) */
404
404
  /* calculating its dimensions carefully is of great importance */
@@ -3,6 +3,10 @@ class YPI93 extends Profile {
3
3
  // Number of pages
4
4
  static pages = 2;
5
5
 
6
+ static partials = {
7
+ YPI93_factors: "samples/YPI93_factors.hbs",
8
+ };
9
+
6
10
  // Labels of the sample
7
11
  labels = {
8
12
  L1_fs: { eng: "ab_father_score", group: 1},
@@ -347,4 +351,4 @@ const Items = {
347
351
  60:f15,61:f15,62:f15,63:f15,64:f15,
348
352
  65:f16,66:f16,67:f16,68:f16,
349
353
  69:f17,70:f17,71:f17,72:f17
350
- }
354
+ }
@@ -0,0 +1,125 @@
1
+ <defs>
2
+ <linearGradient id="neoLongPrimary" x1="0" y1="0" x2="1" y2="0">
3
+ <stop stop-color="{{colors.light}}"/>
4
+ <stop offset="1" stop-color="{{colors.dark}}"/>
5
+ </linearGradient>
6
+ <linearGradient id="neoLongSecondary" x1="0" y1="0" x2="1" y2="0">
7
+ <stop stop-color="#C7D2FE"/>
8
+ <stop offset="1" stop-color="#4338CA"/>
9
+ </linearGradient>
10
+ <clipPath id="neoLongBarClip">
11
+ {{bar trackW 16 (object tl=0 bl=0 tr=2 br=2) (toRad 0)}}
12
+ </clipPath>
13
+ <filter id="neoLongSplit" x="352" y="{{math gridTop '-' 3.5}}" width="7" height="{{math (math gridBottom '-' gridTop) '+' 7}}" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
14
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
15
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
16
+ <feOffset dx="1"/>
17
+ <feGaussianBlur stdDeviation="1.5"/>
18
+ <feComposite in2="hardAlpha" operator="out"/>
19
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"/>
20
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1"/>
21
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1" result="shape"/>
22
+ </filter>
23
+ </defs>
24
+
25
+ <g transform="translate({{padding.x}}, {{padding.y}})">
26
+ {{#if tAxis}}
27
+ <text x="374.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">20</text>
28
+ <text x="464.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">35</text>
29
+ <text x="524.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">45</text>
30
+ <text x="584.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">55</text>
31
+ <text x="644.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">65</text>
32
+ <text x="734.5" y="9" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">80</text>
33
+
34
+ <text x="419.5" y="23" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">بسیار پایین</text>
35
+ <text x="494.5" y="23" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">پایین</text>
36
+ <text x="554.5" y="23" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">طبیعی</text>
37
+ <text x="614.5" y="23" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">بالا</text>
38
+ <text x="689.5" y="23" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">بسیار بالا</text>
39
+ {{else}}
40
+ <text x="354.5" y="14" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">0</text>
41
+ <text x="504.5" y="14" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="middle">50 ٪</text>
42
+ <text x="654.5" y="14" font-size="12" font-weight="400" fill="#94A3B8" text-anchor="start">100 ٪</text>
43
+ {{/if}}
44
+
45
+ <text x="{{rawCenter}}" y="9" font-size="12" font-weight="400" fill="#64748B" text-anchor="middle">نمره خام</text>
46
+ <text x="{{rawCenter}}" y="23" font-size="12" font-weight="400" fill="#64748B" text-anchor="middle">از 32</text>
47
+
48
+ {{#each blocks as |block blockIndex|}}
49
+ <g transform="translate(0, {{math blockIndex '*' 204}})">
50
+ {{#if block.isBlue}}
51
+ <rect y="{{../cardY}}" width="811" height="188" rx="8" fill="#F8FAFC"/>
52
+ <g transform="translate(0, {{../cardY}})">
53
+ {{bar 180 188 (object tr=0 br=0 tl=8 bl=8) (toRad 0) fill='#F1F5F9'}}
54
+ </g>
55
+ {{/if}}
56
+
57
+ <text x="90" y="{{math ../cardY '+' 48}}" dy=".3em" font-size="12" font-weight="500" fill="#64748B" text-anchor="middle">{{block.letter}}</text>
58
+ <text x="90" y="{{math ../cardY '+' 68}}" dy=".3em" font-size="15" font-weight="500" fill="#334155" text-anchor="middle">{{block.fa}}</text>
59
+ <rect x="50" y="{{math ../cardY '+' 88.5}}" width="80" height="1" rx="0.5" fill="#E2E8F0"/>
60
+ <rect x="{{../domainChipX}}" y="{{math ../cardY '+' 101.5}}" width="{{../domainChipW}}" height="20" rx="4" fill="{{ternary block.isBlue ../colors.accent '#4F46E5'}}"/>
61
+ {{#if ../tAxis}}
62
+ <text x="90" y="{{math ../cardY '+' 112}}" dy=".3em" font-size="14" font-weight="600" fill="white" text-anchor="middle">{{block.score}}</text>
63
+ {{else}}
64
+ <text x="90" y="{{math ../cardY '+' 112}}" dy=".3em" font-size="14" font-weight="600" fill="white" text-anchor="middle">{{block.percentage}} ٪</text>
65
+ {{/if}}
66
+ <text x="90" y="{{math ../cardY '+' 138}}" dy=".3em" text-anchor="middle"><tspan font-size="15" font-weight="500" fill="#334155">{{block.mark}}</tspan><tspan font-size="13" font-weight="500" fill="#64748B"> از 192</tspan></text>
67
+
68
+ </g>
69
+ {{/each}}
70
+
71
+ {{#if tAxis}}
72
+ <line x1="374.5" y1="{{gridTop}}" x2="374.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
73
+ <line x1="464.5" y1="{{gridTop}}" x2="464.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
74
+ <line x1="524.5" y1="{{gridTop}}" x2="524.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
75
+ <line x1="584.5" y1="{{gridTop}}" x2="584.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
76
+ <line x1="644.5" y1="{{gridTop}}" x2="644.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
77
+ <line x1="734.5" y1="{{gridTop}}" x2="734.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
78
+ {{else}}
79
+ <line x1="429.5" y1="{{gridTop}}" x2="429.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
80
+ <line x1="504.5" y1="{{gridTop}}" x2="504.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
81
+ <line x1="579.5" y1="{{gridTop}}" x2="579.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
82
+ <line x1="654.5" y1="{{gridTop}}" x2="654.5" y2="{{gridBottom}}" stroke="#E2E8F0" stroke-linecap="round" stroke-dasharray="6 6"/>
83
+ {{/if}}
84
+
85
+ {{#each blocks as |block blockIndex|}}
86
+ <g transform="translate(0, {{math blockIndex '*' 204}})">
87
+ <g transform="translate(0, {{block.facetOffsetY}})">
88
+ {{#each block.facets as |facet facetIndex|}}
89
+ <g transform="translate(0, {{math facetIndex '*' 28}})">
90
+ <g transform="translate(355, {{math ../../cardY '+' 16}})">
91
+ {{bar ../../trackW 16 (object tl=0 bl=0 tr=2 br=2) (toRad 0) fill='#E2E8F0' fill-opacity='0.5'}}
92
+ </g>
93
+ <text x="348" y="{{math ../../cardY '+' 24}}" dy=".3em" font-size="13" font-weight="400" fill="#475569" text-anchor="start">{{facet.fa}}</text>
94
+ <rect x="{{../../rawX}}" y="{{math ../../cardY '+' 16.5}}" width="35" height="15" rx="3.5" stroke="{{ternary block.isBlue ../../colors.stroke '#818CF8'}}" fill="none"/>
95
+ <text x="{{../../rawCenter}}" y="{{math ../../cardY '+' 24}}" dy=".3em" font-size="13" font-weight="500" fill="{{ternary block.isBlue ../../colors.accent '#4F46E5'}}" text-anchor="middle">{{facet.mark}}</text>
96
+ {{#unless ../../tAxis}}
97
+ <text x="{{../../levelX}}" y="{{math ../../cardY '+' 24}}" dy=".3em" font-size="12" font-weight="400" fill="#64748B" text-anchor="middle">{{facet.levelText}}</text>
98
+ {{/unless}}
99
+ </g>
100
+ {{/each}}
101
+ </g>
102
+ </g>
103
+ {{/each}}
104
+
105
+ {{#each blocks as |block blockIndex|}}
106
+ <g transform="translate(0, {{math blockIndex '*' 204}})">
107
+ <g transform="translate(0, {{block.facetOffsetY}})">
108
+ {{#each block.facets as |facet facetIndex|}}
109
+ <g transform="translate(355, {{math (math facetIndex '*' 28) '+' (math ../../cardY '+' 16)}})">
110
+ {{bar facet.barW 16 (object tl=0 bl=0 tr=2 br=2) (toRad 0) fill=(ternary block.isBlue 'url(#neoLongPrimary)' 'url(#neoLongSecondary)') clip-path='url(#neoLongBarClip)'}}
111
+ {{#if ../../tAxis}}
112
+ <text x="{{math facet.barW '+' (ternary facet.inside -4 6)}}" y="8" dy=".3em" font-size="13" font-weight="500" fill="{{ternary facet.inside 'white' (ternary block.isBlue ../../colors.dark '#4338CA')}}" text-anchor="{{ternary facet.inside 'start' 'end'}}">{{facet.score}}</text>
113
+ {{else}}
114
+ <text x="{{math facet.barW '+' (ternary (boolean facet.percentage '<' 24) 6 -4)}}" y="8" dy=".3em" font-size="13" font-weight="500" fill="{{ternary (boolean facet.percentage '<' 24) (ternary block.isBlue ../../colors.dark '#4338CA') 'white'}}" text-anchor="{{ternary (boolean facet.percentage '<' 24) 'end' 'start'}}">{{facet.percentage}} ٪</text>
115
+ {{/if}}
116
+ </g>
117
+ {{/each}}
118
+ </g>
119
+ </g>
120
+ {{/each}}
121
+
122
+ <g opacity="0.5" filter="url(#neoLongSplit)">
123
+ <line x1="354.5" y1="{{gridTop}}" x2="354.5" y2="{{gridBottom}}" stroke="white" stroke-linecap="round"/>
124
+ </g>
125
+ </g>