dabke 0.82.0 → 0.84.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 (341) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +22 -24
  3. package/dist/client.d.ts +39 -3
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/client.schemas.d.ts +118 -18
  7. package/dist/client.schemas.d.ts.map +1 -1
  8. package/dist/client.schemas.js +110 -6
  9. package/dist/client.schemas.js.map +1 -1
  10. package/dist/client.types.d.ts +63 -7
  11. package/dist/client.types.d.ts.map +1 -1
  12. package/dist/client.types.js.map +1 -1
  13. package/dist/cpsat/cost.d.ts +5 -2
  14. package/dist/cpsat/cost.d.ts.map +1 -1
  15. package/dist/cpsat/cost.js +13 -6
  16. package/dist/cpsat/cost.js.map +1 -1
  17. package/dist/cpsat/model-builder.d.ts +42 -61
  18. package/dist/cpsat/model-builder.d.ts.map +1 -1
  19. package/dist/cpsat/model-builder.js +451 -56
  20. package/dist/cpsat/model-builder.js.map +1 -1
  21. package/dist/cpsat/response.d.ts +19 -7
  22. package/dist/cpsat/response.d.ts.map +1 -1
  23. package/dist/cpsat/response.js +48 -9
  24. package/dist/cpsat/response.js.map +1 -1
  25. package/dist/cpsat/rule-descriptor.d.ts +250 -0
  26. package/dist/cpsat/rule-descriptor.d.ts.map +1 -0
  27. package/dist/cpsat/rule-descriptor.js +51 -0
  28. package/dist/cpsat/rule-descriptor.js.map +1 -0
  29. package/dist/cpsat/rules/artifacts.d.ts +9 -0
  30. package/dist/cpsat/rules/artifacts.d.ts.map +1 -0
  31. package/dist/cpsat/rules/artifacts.js +31 -0
  32. package/dist/cpsat/rules/artifacts.js.map +1 -0
  33. package/dist/cpsat/rules/assign-together.d.ts +18 -20
  34. package/dist/cpsat/rules/assign-together.d.ts.map +1 -1
  35. package/dist/cpsat/rules/assign-together.js +90 -54
  36. package/dist/cpsat/rules/assign-together.js.map +1 -1
  37. package/dist/cpsat/rules/assigned-day.d.ts +12 -0
  38. package/dist/cpsat/rules/assigned-day.d.ts.map +1 -0
  39. package/dist/cpsat/rules/assigned-day.js +43 -0
  40. package/dist/cpsat/rules/assigned-day.js.map +1 -0
  41. package/dist/cpsat/rules/assignment-priority.d.ts +15 -29
  42. package/dist/cpsat/rules/assignment-priority.d.ts.map +1 -1
  43. package/dist/cpsat/rules/assignment-priority.js +47 -50
  44. package/dist/cpsat/rules/assignment-priority.js.map +1 -1
  45. package/dist/cpsat/rules/assignment-terms.d.ts +6 -0
  46. package/dist/cpsat/rules/assignment-terms.d.ts.map +1 -0
  47. package/dist/cpsat/rules/assignment-terms.js +19 -0
  48. package/dist/cpsat/rules/assignment-terms.js.map +1 -0
  49. package/dist/cpsat/rules/concurrent-intervals.d.ts +19 -0
  50. package/dist/cpsat/rules/concurrent-intervals.d.ts.map +1 -0
  51. package/dist/cpsat/rules/concurrent-intervals.js +57 -0
  52. package/dist/cpsat/rules/concurrent-intervals.js.map +1 -0
  53. package/dist/cpsat/rules/cost-utils.d.ts +1 -3
  54. package/dist/cpsat/rules/cost-utils.d.ts.map +1 -1
  55. package/dist/cpsat/rules/cost-utils.js +0 -7
  56. package/dist/cpsat/rules/cost-utils.js.map +1 -1
  57. package/dist/cpsat/rules/day-cost-multiplier.d.ts +10 -10
  58. package/dist/cpsat/rules/day-cost-multiplier.d.ts.map +1 -1
  59. package/dist/cpsat/rules/day-cost-multiplier.js +88 -77
  60. package/dist/cpsat/rules/day-cost-multiplier.js.map +1 -1
  61. package/dist/cpsat/rules/day-cost-surcharge.d.ts +10 -10
  62. package/dist/cpsat/rules/day-cost-surcharge.d.ts.map +1 -1
  63. package/dist/cpsat/rules/day-cost-surcharge.js +76 -65
  64. package/dist/cpsat/rules/day-cost-surcharge.js.map +1 -1
  65. package/dist/cpsat/rules/index.d.ts +30 -21
  66. package/dist/cpsat/rules/index.d.ts.map +1 -1
  67. package/dist/cpsat/rules/index.js +30 -21
  68. package/dist/cpsat/rules/index.js.map +1 -1
  69. package/dist/cpsat/rules/location-preference.d.ts +14 -21
  70. package/dist/cpsat/rules/location-preference.d.ts.map +1 -1
  71. package/dist/cpsat/rules/location-preference.js +45 -45
  72. package/dist/cpsat/rules/location-preference.js.map +1 -1
  73. package/dist/cpsat/rules/max-concurrent-assignments.d.ts +46 -0
  74. package/dist/cpsat/rules/max-concurrent-assignments.d.ts.map +1 -0
  75. package/dist/cpsat/rules/max-concurrent-assignments.js +121 -0
  76. package/dist/cpsat/rules/max-concurrent-assignments.js.map +1 -0
  77. package/dist/cpsat/rules/max-consecutive-days.d.ts +18 -17
  78. package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
  79. package/dist/cpsat/rules/max-consecutive-days.js +67 -66
  80. package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
  81. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts +45 -0
  82. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts.map +1 -0
  83. package/dist/cpsat/rules/max-days-of-week-per-period.js +95 -0
  84. package/dist/cpsat/rules/max-days-of-week-per-period.js.map +1 -0
  85. package/dist/cpsat/rules/max-days-week.d.ts +30 -0
  86. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -0
  87. package/dist/cpsat/rules/max-days-week.js +83 -0
  88. package/dist/cpsat/rules/max-days-week.js.map +1 -0
  89. package/dist/cpsat/rules/max-hours-day.d.ts +14 -31
  90. package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
  91. package/dist/cpsat/rules/max-hours-day.js +56 -72
  92. package/dist/cpsat/rules/max-hours-day.js.map +1 -1
  93. package/dist/cpsat/rules/max-hours-week.d.ts +15 -31
  94. package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
  95. package/dist/cpsat/rules/max-hours-week.js +60 -75
  96. package/dist/cpsat/rules/max-hours-week.js.map +1 -1
  97. package/dist/cpsat/rules/max-shifts-day.d.ts +17 -33
  98. package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
  99. package/dist/cpsat/rules/max-shifts-day.js +57 -73
  100. package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
  101. package/dist/cpsat/rules/min-consecutive-days.d.ts +18 -18
  102. package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
  103. package/dist/cpsat/rules/min-consecutive-days.js +123 -94
  104. package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
  105. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts +35 -0
  106. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts.map +1 -0
  107. package/dist/cpsat/rules/min-days-of-week-per-period.js +108 -0
  108. package/dist/cpsat/rules/min-days-of-week-per-period.js.map +1 -0
  109. package/dist/cpsat/rules/min-days-week.d.ts +21 -0
  110. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -0
  111. package/dist/cpsat/rules/min-days-week.js +95 -0
  112. package/dist/cpsat/rules/min-days-week.js.map +1 -0
  113. package/dist/cpsat/rules/min-hours-day.d.ts +14 -17
  114. package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
  115. package/dist/cpsat/rules/min-hours-day.js +72 -54
  116. package/dist/cpsat/rules/min-hours-day.js.map +1 -1
  117. package/dist/cpsat/rules/min-hours-week.d.ts +15 -18
  118. package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
  119. package/dist/cpsat/rules/min-hours-week.js +75 -57
  120. package/dist/cpsat/rules/min-hours-week.js.map +1 -1
  121. package/dist/cpsat/rules/min-rest-between-shifts.d.ts +14 -17
  122. package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
  123. package/dist/cpsat/rules/min-rest-between-shifts.js +148 -138
  124. package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
  125. package/dist/cpsat/rules/minimize-cost.d.ts +2 -18
  126. package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
  127. package/dist/cpsat/rules/minimize-cost.js +151 -163
  128. package/dist/cpsat/rules/minimize-cost.js.map +1 -1
  129. package/dist/cpsat/rules/must-assign.d.ts +12 -0
  130. package/dist/cpsat/rules/must-assign.d.ts.map +1 -0
  131. package/dist/cpsat/rules/must-assign.js +54 -0
  132. package/dist/cpsat/rules/must-assign.js.map +1 -0
  133. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts +6 -10
  134. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
  135. package/dist/cpsat/rules/overtime-daily-multiplier.js +118 -112
  136. package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
  137. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts +6 -11
  138. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
  139. package/dist/cpsat/rules/overtime-daily-surcharge.js +104 -99
  140. package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
  141. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +9 -21
  142. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
  143. package/dist/cpsat/rules/overtime-tiered-multiplier.js +181 -199
  144. package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
  145. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts +13 -12
  146. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
  147. package/dist/cpsat/rules/overtime-weekly-multiplier.js +143 -143
  148. package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
  149. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts +7 -11
  150. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
  151. package/dist/cpsat/rules/overtime-weekly-surcharge.js +124 -119
  152. package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
  153. package/dist/cpsat/rules/pattern-eligibility.d.ts +6 -0
  154. package/dist/cpsat/rules/pattern-eligibility.d.ts.map +1 -0
  155. package/dist/cpsat/rules/pattern-eligibility.js +16 -0
  156. package/dist/cpsat/rules/pattern-eligibility.js.map +1 -0
  157. package/dist/cpsat/rules/pattern-time.d.ts +5 -0
  158. package/dist/cpsat/rules/pattern-time.d.ts.map +1 -0
  159. package/dist/cpsat/rules/pattern-time.js +20 -0
  160. package/dist/cpsat/rules/pattern-time.js.map +1 -0
  161. package/dist/cpsat/rules/registry.d.ts +217 -27
  162. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  163. package/dist/cpsat/rules/registry.js +98 -31
  164. package/dist/cpsat/rules/registry.js.map +1 -1
  165. package/dist/cpsat/rules/resolver.d.ts +9 -7
  166. package/dist/cpsat/rules/resolver.d.ts.map +1 -1
  167. package/dist/cpsat/rules/resolver.js +19 -18
  168. package/dist/cpsat/rules/resolver.js.map +1 -1
  169. package/dist/cpsat/rules/role-preference.d.ts +24 -0
  170. package/dist/cpsat/rules/role-preference.d.ts.map +1 -0
  171. package/dist/cpsat/rules/role-preference.js +72 -0
  172. package/dist/cpsat/rules/role-preference.js.map +1 -0
  173. package/dist/cpsat/rules/rules.types.d.ts +93 -17
  174. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  175. package/dist/cpsat/rules/scope.types.d.ts +25 -12
  176. package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
  177. package/dist/cpsat/rules/scope.types.js +14 -19
  178. package/dist/cpsat/rules/scope.types.js.map +1 -1
  179. package/dist/cpsat/rules/target-days-week.d.ts +31 -0
  180. package/dist/cpsat/rules/target-days-week.d.ts.map +1 -0
  181. package/dist/cpsat/rules/target-days-week.js +80 -0
  182. package/dist/cpsat/rules/target-days-week.js.map +1 -0
  183. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts +33 -0
  184. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts.map +1 -0
  185. package/dist/cpsat/rules/target-peak-concurrent-assignments.js +146 -0
  186. package/dist/cpsat/rules/target-peak-concurrent-assignments.js.map +1 -0
  187. package/dist/cpsat/rules/time-cost-surcharge.d.ts +15 -14
  188. package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
  189. package/dist/cpsat/rules/time-cost-surcharge.js +82 -96
  190. package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
  191. package/dist/cpsat/rules/time-off.d.ts +21 -57
  192. package/dist/cpsat/rules/time-off.d.ts.map +1 -1
  193. package/dist/cpsat/rules/time-off.js +114 -127
  194. package/dist/cpsat/rules/time-off.js.map +1 -1
  195. package/dist/cpsat/rules/variables.d.ts +4 -0
  196. package/dist/cpsat/rules/variables.d.ts.map +1 -0
  197. package/dist/cpsat/rules/variables.js +10 -0
  198. package/dist/cpsat/rules/variables.js.map +1 -0
  199. package/dist/cpsat/rules.d.ts +20 -3
  200. package/dist/cpsat/rules.d.ts.map +1 -1
  201. package/dist/cpsat/rules.js +19 -2
  202. package/dist/cpsat/rules.js.map +1 -1
  203. package/dist/cpsat/semantic-time.d.ts +7 -6
  204. package/dist/cpsat/semantic-time.d.ts.map +1 -1
  205. package/dist/cpsat/semantic-time.js +15 -28
  206. package/dist/cpsat/semantic-time.js.map +1 -1
  207. package/dist/cpsat/types.d.ts +47 -4
  208. package/dist/cpsat/types.d.ts.map +1 -1
  209. package/dist/cpsat/types.js +24 -1
  210. package/dist/cpsat/types.js.map +1 -1
  211. package/dist/cpsat/utils.d.ts +23 -6
  212. package/dist/cpsat/utils.d.ts.map +1 -1
  213. package/dist/cpsat/utils.js +76 -15
  214. package/dist/cpsat/utils.js.map +1 -1
  215. package/dist/cpsat/validation-reporter.d.ts +6 -2
  216. package/dist/cpsat/validation-reporter.d.ts.map +1 -1
  217. package/dist/cpsat/validation-reporter.js +122 -10
  218. package/dist/cpsat/validation-reporter.js.map +1 -1
  219. package/dist/cpsat/validation.types.d.ts +21 -10
  220. package/dist/cpsat/validation.types.d.ts.map +1 -1
  221. package/dist/datetime.utils.d.ts +7 -13
  222. package/dist/datetime.utils.d.ts.map +1 -1
  223. package/dist/datetime.utils.js +29 -36
  224. package/dist/datetime.utils.js.map +1 -1
  225. package/dist/index.d.ts +15 -9
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +11 -4
  228. package/dist/index.js.map +1 -1
  229. package/dist/schedule/cost.d.ts +192 -0
  230. package/dist/schedule/cost.d.ts.map +1 -0
  231. package/dist/schedule/cost.js +151 -0
  232. package/dist/schedule/cost.js.map +1 -0
  233. package/dist/schedule/coverage.d.ts +114 -0
  234. package/dist/schedule/coverage.d.ts.map +1 -0
  235. package/dist/schedule/coverage.js +56 -0
  236. package/dist/schedule/coverage.js.map +1 -0
  237. package/dist/schedule/definition.d.ts +346 -0
  238. package/dist/schedule/definition.d.ts.map +1 -0
  239. package/dist/schedule/definition.js +668 -0
  240. package/dist/schedule/definition.js.map +1 -0
  241. package/dist/schedule/index.d.ts +67 -0
  242. package/dist/schedule/index.d.ts.map +1 -0
  243. package/dist/schedule/index.js +69 -0
  244. package/dist/schedule/index.js.map +1 -0
  245. package/dist/schedule/rules.d.ts +678 -0
  246. package/dist/schedule/rules.d.ts.map +1 -0
  247. package/dist/schedule/rules.js +554 -0
  248. package/dist/schedule/rules.js.map +1 -0
  249. package/dist/schedule/shift-patterns.d.ts +17 -0
  250. package/dist/schedule/shift-patterns.d.ts.map +1 -0
  251. package/dist/schedule/shift-patterns.js +24 -0
  252. package/dist/schedule/shift-patterns.js.map +1 -0
  253. package/dist/schedule/time-periods.d.ts +79 -0
  254. package/dist/schedule/time-periods.d.ts.map +1 -0
  255. package/dist/schedule/time-periods.js +101 -0
  256. package/dist/schedule/time-periods.js.map +1 -0
  257. package/dist/types.d.ts +67 -3
  258. package/dist/types.d.ts.map +1 -1
  259. package/dist/types.js +64 -0
  260. package/dist/types.js.map +1 -1
  261. package/package.json +8 -14
  262. package/solver/src/solver/models.py +41 -4
  263. package/solver/src/solver/solver.py +546 -157
  264. package/solver/tests/test_solver.py +363 -7
  265. package/src/client.schemas.ts +127 -10
  266. package/src/client.ts +3 -0
  267. package/src/client.types.ts +73 -7
  268. package/src/cpsat/cost.ts +17 -7
  269. package/src/cpsat/model-builder.ts +614 -129
  270. package/src/cpsat/response.ts +57 -13
  271. package/src/cpsat/rule-descriptor.ts +311 -0
  272. package/src/cpsat/rules/artifacts.ts +56 -0
  273. package/src/cpsat/rules/assign-together.ts +104 -69
  274. package/src/cpsat/rules/assigned-day.ts +70 -0
  275. package/src/cpsat/rules/assignment-priority.ts +54 -58
  276. package/src/cpsat/rules/assignment-terms.ts +43 -0
  277. package/src/cpsat/rules/concurrent-intervals.ts +93 -0
  278. package/src/cpsat/rules/cost-utils.ts +1 -9
  279. package/src/cpsat/rules/day-cost-multiplier.ts +101 -81
  280. package/src/cpsat/rules/day-cost-surcharge.ts +91 -70
  281. package/src/cpsat/rules/index.ts +30 -21
  282. package/src/cpsat/rules/location-preference.ts +47 -52
  283. package/src/cpsat/rules/max-concurrent-assignments.ts +170 -0
  284. package/src/cpsat/rules/max-consecutive-days.ts +74 -91
  285. package/src/cpsat/rules/max-days-of-week-per-period.ts +127 -0
  286. package/src/cpsat/rules/max-days-week.ts +117 -0
  287. package/src/cpsat/rules/max-hours-day.ts +64 -84
  288. package/src/cpsat/rules/max-hours-week.ts +74 -90
  289. package/src/cpsat/rules/max-shifts-day.ts +65 -85
  290. package/src/cpsat/rules/min-consecutive-days.ts +161 -127
  291. package/src/cpsat/rules/min-days-of-week-per-period.ts +144 -0
  292. package/src/cpsat/rules/min-days-week.ts +122 -0
  293. package/src/cpsat/rules/min-hours-day.ts +79 -58
  294. package/src/cpsat/rules/min-hours-week.ts +87 -62
  295. package/src/cpsat/rules/min-rest-between-shifts.ts +191 -178
  296. package/src/cpsat/rules/minimize-cost.ts +175 -188
  297. package/src/cpsat/rules/must-assign.ts +71 -0
  298. package/src/cpsat/rules/overtime-daily-multiplier.ts +158 -140
  299. package/src/cpsat/rules/overtime-daily-surcharge.ts +141 -126
  300. package/src/cpsat/rules/overtime-tiered-multiplier.ts +234 -253
  301. package/src/cpsat/rules/overtime-weekly-multiplier.ts +183 -175
  302. package/src/cpsat/rules/overtime-weekly-surcharge.ts +161 -150
  303. package/src/cpsat/rules/pattern-eligibility.ts +26 -0
  304. package/src/cpsat/rules/pattern-time.ts +30 -0
  305. package/src/cpsat/rules/registry.ts +140 -56
  306. package/src/cpsat/rules/resolver.ts +58 -30
  307. package/src/cpsat/rules/role-preference.ts +92 -0
  308. package/src/cpsat/rules/rules.types.ts +92 -17
  309. package/src/cpsat/rules/scope.types.ts +32 -27
  310. package/src/cpsat/rules/target-days-week.ts +105 -0
  311. package/src/cpsat/rules/target-peak-concurrent-assignments.ts +212 -0
  312. package/src/cpsat/rules/time-cost-surcharge.ts +116 -122
  313. package/src/cpsat/rules/time-off.ts +154 -163
  314. package/src/cpsat/rules/variables.ts +11 -0
  315. package/src/cpsat/rules.ts +43 -17
  316. package/src/cpsat/semantic-time.ts +29 -43
  317. package/src/cpsat/types.ts +53 -4
  318. package/src/cpsat/utils.ts +92 -20
  319. package/src/cpsat/validation-reporter.ts +170 -19
  320. package/src/cpsat/validation.types.ts +22 -11
  321. package/src/datetime.utils.ts +45 -44
  322. package/src/index.ts +72 -15
  323. package/src/schedule/cost.ts +221 -0
  324. package/src/schedule/coverage.ts +164 -0
  325. package/src/schedule/definition.ts +1447 -0
  326. package/src/schedule/index.ts +132 -0
  327. package/src/schedule/rules.ts +1028 -0
  328. package/src/schedule/shift-patterns.ts +29 -0
  329. package/src/schedule/time-periods.ts +120 -0
  330. package/src/types.ts +114 -2
  331. package/dist/llms.d.ts +0 -2
  332. package/dist/llms.d.ts.map +0 -1
  333. package/dist/llms.js +0 -3
  334. package/dist/llms.js.map +0 -1
  335. package/dist/schedule.d.ts +0 -917
  336. package/dist/schedule.d.ts.map +0 -1
  337. package/dist/schedule.js +0 -1323
  338. package/dist/schedule.js.map +0 -1
  339. package/llms.txt +0 -758
  340. package/src/llms.ts +0 -3
  341. package/src/schedule.ts +0 -1960
@@ -1,5 +1,5 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
2
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
3
3
  import { priorityToPenalty } from "../utils.js";
4
4
  import {
5
5
  PrioritySchema,
@@ -8,8 +8,11 @@ import {
8
8
  resolveMembersFromScope,
9
9
  ruleGroup,
10
10
  } from "./scope.types.js";
11
+ import { assignmentVarsForDay } from "./assignment-terms.js";
12
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
13
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
11
14
 
12
- const MaxConsecutiveDaysSchema = z
15
+ export const MaxConsecutiveDaysSchema = z
13
16
  .object({
14
17
  days: z.number().min(0),
15
18
  priority: PrioritySchema,
@@ -17,103 +20,83 @@ const MaxConsecutiveDaysSchema = z
17
20
  .and(entityScope(["members", "roles", "skills"]));
18
21
 
19
22
  /**
20
- * Configuration for {@link createMaxConsecutiveDaysRule}.
21
- *
22
- * - `days` (required): maximum consecutive days allowed
23
- * - `priority` (required): how strictly the solver enforces this rule
24
- *
25
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
23
+ * Configuration for {@link maxConsecutiveDaysRuleDescriptor}.
26
24
  */
27
25
  export type MaxConsecutiveDaysConfig = z.infer<typeof MaxConsecutiveDaysSchema>;
28
26
 
29
27
  /**
30
- * Limits how many consecutive days a person can be assigned.
28
+ * Low-level descriptor for the `max-consecutive-days` rule.
31
29
  *
32
- * @param config - See {@link MaxConsecutiveDaysConfig}
33
- * @example
34
- * ```ts
35
- * createMaxConsecutiveDaysRule({ days: 5, priority: "MANDATORY" });
36
- * ```
30
+ * @remarks
31
+ * This rule limits the length of each assignment streak by counting assigned
32
+ * days in every sliding window of `days + 1` days.
33
+ *
34
+ * @category Rules
37
35
  */
38
- export function createMaxConsecutiveDaysRule(config: MaxConsecutiveDaysConfig): CompilationRule {
39
- const parsed = MaxConsecutiveDaysSchema.parse(config);
40
- const scope = parseEntityScope(parsed);
41
- const { days, priority } = parsed;
42
- const windowSize = days + 1;
43
- const group = ruleGroup(`max-consecutive-days:${days}`, `Max ${days} consecutive days`, scope);
44
-
45
- return {
46
- compile(b) {
47
- const members = resolveMembersFromScope(scope, b.members);
36
+ export const maxConsecutiveDaysRuleDescriptor = defineRuleDescriptor({
37
+ name: "max-consecutive-days",
38
+ schema: MaxConsecutiveDaysSchema,
39
+ compile(config, ctx) {
40
+ const scope = parseEntityScope(config);
41
+ const { days, priority } = config;
42
+ const windowSize = days + 1;
43
+ const group = ruleGroup(`max-consecutive-days:${days}`, `Max ${days} consecutive days`, scope);
44
+ const members = resolveMembersFromScope(scope, [...ctx.members]);
48
45
 
49
- for (const emp of members) {
50
- for (let i = 0; i <= b.days.length - windowSize; i++) {
51
- const windowDays = b.days.slice(i, i + windowSize);
46
+ const artifacts = members.flatMap((member) => {
47
+ const supportArtifacts = ctx.days.flatMap(
48
+ (day) =>
49
+ buildAssignedDayIndicator({
50
+ memberId: member.id,
51
+ day,
52
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
53
+ variableName: `assigned_${member.id}_${day.iso}`,
54
+ }).artifacts,
55
+ );
52
56
 
53
- const worksDayVars: string[] = [];
54
- for (const day of windowDays) {
55
- const worksVar = b.boolVar(`works_${emp.id}_${day}`);
56
- worksDayVars.push(worksVar);
57
-
58
- const dayAssignments = b.shiftPatterns
59
- .filter((p) => b.canAssign(emp, p) && b.patternAvailableOnDay(p, day))
60
- .map((p) => b.assignment(emp.id, p.id, day));
57
+ const windowArtifacts = Array.from(
58
+ { length: Math.max(0, ctx.days.length - windowSize + 1) },
59
+ (_, index) => {
60
+ const windowDays = ctx.days.slice(index, index + windowSize);
61
+ const windowStart = windowDays[0]!;
62
+ const terms = windowDays.map((day) => ({
63
+ var: `assigned_${member.id}_${day.iso}`,
64
+ coeff: 1,
65
+ }));
66
+ const description = `${member.id} max ${days} consecutive days from ${windowStart.iso}`;
67
+ const context = { memberIds: [member.id], days: windowDays.map((day) => day.iso) };
68
+ const constraintId = `max-consecutive-days:${member.id}:${windowStart.iso}`;
61
69
 
62
- if (dayAssignments.length === 0) {
63
- b.addLinear([{ var: worksVar, coeff: 1 }], "==", 0);
64
- } else {
65
- for (const assignVar of dayAssignments) {
66
- b.addLinear(
67
- [
68
- { var: worksVar, coeff: 1 },
69
- { var: assignVar, coeff: -1 },
70
- ],
71
- ">=",
72
- 0,
73
- );
74
- }
75
- b.addLinear(
76
- [
77
- { var: worksVar, coeff: 1 },
78
- ...dayAssignments.map((v) => ({ var: v, coeff: -1 })),
79
- ],
80
- "<=",
81
- 0,
82
- );
83
- }
84
- }
70
+ return priority === "MANDATORY"
71
+ ? hardConstraint({
72
+ group,
73
+ description,
74
+ context,
75
+ validation: reportValidation(constraintId),
76
+ terms,
77
+ comparator: "<=",
78
+ targetValue: days,
79
+ })
80
+ : softConstraint({
81
+ group,
82
+ description,
83
+ context,
84
+ validation: reportValidation(),
85
+ terms,
86
+ comparator: "<=",
87
+ targetValue: days,
88
+ penalty: priorityToPenalty(priority),
89
+ constraintId,
90
+ });
91
+ },
92
+ );
85
93
 
86
- const windowStart = windowDays[0]!;
87
- const constraintId = `max-consecutive-days:${emp.id}:${windowStart}`;
94
+ return supportArtifacts.concat(windowArtifacts);
95
+ });
88
96
 
89
- if (priority === "MANDATORY") {
90
- b.addLinear(
91
- worksDayVars.map((v) => ({ var: v, coeff: 1 })),
92
- "<=",
93
- days,
94
- );
95
- } else {
96
- b.addSoftLinear(
97
- worksDayVars.map((v) => ({ var: v, coeff: 1 })),
98
- "<=",
99
- days,
100
- priorityToPenalty(priority),
101
- constraintId,
102
- );
103
- b.reporter.trackConstraint({
104
- id: constraintId,
105
- type: "rule",
106
- rule: "max-consecutive-days",
107
- description: `${emp.id} max ${days} consecutive days from ${windowStart}`,
108
- targetValue: days,
109
- comparator: "<=",
110
- day: windowStart,
111
- context: { memberIds: [emp.id], days: windowDays },
112
- group,
113
- });
114
- }
115
- }
116
- }
117
- },
118
- };
119
- }
97
+ return {
98
+ rule: "max-consecutive-days",
99
+ artifacts,
100
+ };
101
+ },
102
+ });
@@ -0,0 +1,127 @@
1
+ import * as z from "zod";
2
+ import { DayOfWeekSchema } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
+ import { groupWeekChunks, priorityToPenalty, splitIntoMonths } from "../utils.js";
5
+ import {
6
+ PrioritySchema,
7
+ entityScope,
8
+ parseEntityScope,
9
+ resolveMembersFromScope,
10
+ ruleGroup,
11
+ } from "./scope.types.js";
12
+ import { assignmentVarsForDay } from "./assignment-terms.js";
13
+ import { assignedDayVariableName } from "./variables.js";
14
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
15
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
16
+
17
+ const PeriodSchema = z.discriminatedUnion("type", [
18
+ z.object({ type: z.literal("weeks"), value: z.number().int().min(1) }),
19
+ z.object({ type: z.literal("months"), value: z.number().int().min(1) }),
20
+ ]);
21
+
22
+ const MaxDaysOfWeekPerPeriodBase = z.object({
23
+ days: z.number().int().min(0),
24
+ dayOfWeek: z.array(DayOfWeekSchema).nonempty(),
25
+ period: PeriodSchema,
26
+ priority: PrioritySchema,
27
+ });
28
+
29
+ export const MaxDaysOfWeekPerPeriodSchema = MaxDaysOfWeekPerPeriodBase.and(
30
+ entityScope(["members", "roles", "skills"]),
31
+ );
32
+
33
+ /**
34
+ * Configuration for {@link maxDaysOfWeekPerPeriodRuleDescriptor}.
35
+ */
36
+ export type MaxDaysOfWeekPerPeriodConfig = z.infer<typeof MaxDaysOfWeekPerPeriodSchema>;
37
+
38
+ /**
39
+ * Low-level descriptor for the `max-days-of-week-per-period` rule.
40
+ *
41
+ * @remarks
42
+ * This rule counts assigned days matching the configured days of the week.
43
+ * Week-based periods align to `weekStartsOn`; month-based periods align to
44
+ * calendar month boundaries.
45
+ *
46
+ * @category Rules
47
+ */
48
+ export const maxDaysOfWeekPerPeriodRuleDescriptor = defineRuleDescriptor({
49
+ name: "max-days-of-week-per-period",
50
+ schema: MaxDaysOfWeekPerPeriodSchema,
51
+ compile(config, ctx) {
52
+ const entityScopeValue = parseEntityScope(config);
53
+ const { days, dayOfWeek, period, priority } = config;
54
+ const dowLabel = dayOfWeek.toSorted().join(",");
55
+ const periodLabel = `${period.value}${period.type === "weeks" ? "w" : "m"}`;
56
+ const group = ruleGroup(
57
+ `max-days-of-week-per-period:${days}:${dowLabel}:${periodLabel}`,
58
+ `Max ${days} ${dowLabel} per ${period.value} ${period.type}`,
59
+ entityScopeValue,
60
+ );
61
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
62
+ const targetDows = new Set(dayOfWeek);
63
+ const chunks =
64
+ period.type === "weeks"
65
+ ? groupWeekChunks([...ctx.days], period.value, ctx.weekStartsOn)
66
+ : splitIntoMonths([...ctx.days], period.value);
67
+
68
+ const artifacts = targetMembers.flatMap((member) =>
69
+ chunks.flatMap((chunkDays) => {
70
+ const chunkStart = chunkDays[0];
71
+ if (!chunkStart) return [];
72
+
73
+ const matchingDays = chunkDays.filter((day) => targetDows.has(day.dayOfWeek));
74
+ if (matchingDays.length === 0) return [];
75
+
76
+ const supportArtifacts = matchingDays.flatMap(
77
+ (day) =>
78
+ buildAssignedDayIndicator({
79
+ memberId: member.id,
80
+ day,
81
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
82
+ }).artifacts,
83
+ );
84
+
85
+ const assignedDayVars = matchingDays
86
+ .filter((day) => assignmentVarsForDay(member, day, ctx.shiftPatterns).length > 0)
87
+ .map((day) => assignedDayVariableName(member.id, day.iso));
88
+ if (assignedDayVars.length === 0) return supportArtifacts;
89
+
90
+ const description = `${member.id} max ${days} ${dowLabel} in period starting ${chunkStart.iso}`;
91
+ const context = { memberIds: [member.id], days: matchingDays.map((day) => day.iso) };
92
+ const constraintId = `max-days-of-week-per-period:${member.id}:${chunkStart.iso}`;
93
+ const terms = assignedDayVars.map((varName) => ({ var: varName, coeff: 1 }));
94
+
95
+ const finalArtifact =
96
+ priority === "MANDATORY"
97
+ ? hardConstraint({
98
+ group,
99
+ description,
100
+ context,
101
+ validation: reportValidation(constraintId),
102
+ terms,
103
+ comparator: "<=",
104
+ targetValue: days,
105
+ })
106
+ : softConstraint({
107
+ group,
108
+ description,
109
+ context,
110
+ validation: reportValidation(),
111
+ terms,
112
+ comparator: "<=",
113
+ targetValue: days,
114
+ penalty: priorityToPenalty(priority),
115
+ constraintId,
116
+ });
117
+
118
+ return supportArtifacts.concat(finalArtifact);
119
+ }),
120
+ );
121
+
122
+ return {
123
+ rule: "max-days-of-week-per-period",
124
+ artifacts,
125
+ };
126
+ },
127
+ });
@@ -0,0 +1,117 @@
1
+ import * as z from "zod";
2
+ import { DayOfWeekSchema } from "../../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
+ import { priorityToPenalty, splitIntoWeeks } from "../utils.js";
5
+ import {
6
+ PrioritySchema,
7
+ entityScope,
8
+ parseEntityScope,
9
+ parseTimeScope,
10
+ resolveActiveDaysFromScope,
11
+ resolveMembersFromScope,
12
+ ruleGroup,
13
+ timeScope,
14
+ } from "./scope.types.js";
15
+ import { assignmentVarsForDay } from "./assignment-terms.js";
16
+ import { assignedDayVariableName } from "./variables.js";
17
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
18
+ import { buildAssignedDayIndicator } from "./assigned-day.js";
19
+
20
+ const MaxDaysWeekBase = z.object({
21
+ days: z.number().int().min(0),
22
+ priority: PrioritySchema,
23
+ weekStartsOn: DayOfWeekSchema.optional(),
24
+ });
25
+
26
+ export const MaxDaysWeekSchema = MaxDaysWeekBase.and(
27
+ entityScope(["members", "roles", "skills"]),
28
+ ).and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
29
+
30
+ /**
31
+ * Configuration for {@link maxDaysWeekRuleDescriptor}.
32
+ */
33
+ export type MaxDaysWeekConfig = z.infer<typeof MaxDaysWeekSchema>;
34
+
35
+ /**
36
+ * Low-level descriptor for the `max-days-week` rule.
37
+ *
38
+ * @remarks
39
+ * This rule counts assigned days, not assigned shifts. Multiple assignments on
40
+ * the same day still count as one assigned day.
41
+ *
42
+ * @category Rules
43
+ */
44
+ export const maxDaysWeekRuleDescriptor = defineRuleDescriptor({
45
+ name: "max-days-week",
46
+ schema: MaxDaysWeekSchema,
47
+ compile(config, ctx) {
48
+ const entityScopeValue = parseEntityScope(config);
49
+ const timeScopeValue = parseTimeScope(config);
50
+ const { days, priority, weekStartsOn } = config;
51
+ const group = ruleGroup(
52
+ `max-days-week:${days}`,
53
+ `Max ${days}d per week`,
54
+ entityScopeValue,
55
+ timeScopeValue,
56
+ );
57
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
58
+ const activeDays = resolveActiveDaysFromScope(timeScopeValue, [...ctx.days]);
59
+ const weeks = splitIntoWeeks(activeDays, weekStartsOn ?? ctx.weekStartsOn);
60
+
61
+ const artifacts = targetMembers.flatMap((member) =>
62
+ weeks.flatMap((weekDays) => {
63
+ const weekStart = weekDays[0];
64
+ if (!weekStart) return [];
65
+
66
+ const supportArtifacts = weekDays.flatMap(
67
+ (day) =>
68
+ buildAssignedDayIndicator({
69
+ memberId: member.id,
70
+ day,
71
+ assignmentVars: assignmentVarsForDay(member, day, ctx.shiftPatterns),
72
+ }).artifacts,
73
+ );
74
+
75
+ const assignedDayVars = weekDays
76
+ .filter((day) => assignmentVarsForDay(member, day, ctx.shiftPatterns).length > 0)
77
+ .map((day) => assignedDayVariableName(member.id, day.iso));
78
+ if (assignedDayVars.length === 0) return supportArtifacts;
79
+
80
+ const description = `${member.id} max ${days}d in week starting ${weekStart.iso}`;
81
+ const context = { memberIds: [member.id], days: weekDays.map((day) => day.iso) };
82
+ const constraintId = `max-days-week:${member.id}:${weekStart.iso}`;
83
+ const terms = assignedDayVars.map((varName) => ({ var: varName, coeff: 1 }));
84
+
85
+ const finalArtifact =
86
+ priority === "MANDATORY"
87
+ ? hardConstraint({
88
+ group,
89
+ description,
90
+ context,
91
+ validation: reportValidation(constraintId),
92
+ terms,
93
+ comparator: "<=",
94
+ targetValue: days,
95
+ })
96
+ : softConstraint({
97
+ group,
98
+ description,
99
+ context,
100
+ validation: reportValidation(),
101
+ terms,
102
+ comparator: "<=",
103
+ targetValue: days,
104
+ penalty: priorityToPenalty(priority),
105
+ constraintId,
106
+ });
107
+
108
+ return supportArtifacts.concat(finalArtifact);
109
+ }),
110
+ );
111
+
112
+ return {
113
+ rule: "max-days-week",
114
+ artifacts,
115
+ };
116
+ },
117
+ });
@@ -1,19 +1,21 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
3
- import type { Term } from "../types.js";
2
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
3
  import { priorityToPenalty } from "../utils.js";
5
4
  import {
6
5
  PrioritySchema,
7
6
  entityScope,
8
- timeScope,
9
7
  parseEntityScope,
10
8
  parseTimeScope,
11
- resolveMembersFromScope,
12
9
  resolveActiveDaysFromScope,
10
+ resolveMembersFromScope,
13
11
  ruleGroup,
12
+ timeScope,
14
13
  } from "./scope.types.js";
14
+ import { assignmentTermsForDay } from "./assignment-terms.js";
15
+ import { patternDurationMinutes } from "./pattern-time.js";
16
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
15
17
 
16
- const MaxHoursDaySchema = z
18
+ export const MaxHoursDaySchema = z
17
19
  .object({
18
20
  hours: z.number().min(0),
19
21
  priority: PrioritySchema,
@@ -22,92 +24,70 @@ const MaxHoursDaySchema = z
22
24
  .and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
23
25
 
24
26
  /**
25
- * Configuration for {@link createMaxHoursDayRule}.
26
- *
27
- * - `hours` (required): maximum hours allowed per day
28
- * - `priority` (required): how strictly the solver enforces this rule
29
- *
30
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
31
- * Time scoping (at most one, optional): `dateRange`, `specificDates`, `dayOfWeek`, `recurringPeriods`
27
+ * Configuration for {@link maxHoursDayRuleDescriptor}.
32
28
  */
33
29
  export type MaxHoursDayConfig = z.infer<typeof MaxHoursDaySchema>;
34
30
 
35
31
  /**
36
- * Limits how many hours a person can work in a single day.
37
- *
38
- * @param config - See {@link MaxHoursDayConfig}
39
- * @example Limit everyone to 8 hours per day
40
- * ```ts
41
- * createMaxHoursDayRule({
42
- * hours: 8,
43
- * priority: "MANDATORY",
44
- * });
45
- * ```
32
+ * Low-level descriptor for the `max-hours-day` rule.
46
33
  *
47
- * @example Students limited to 4 hours on weekdays during term
48
- * ```ts
49
- * createMaxHoursDayRule({
50
- * roleIds: ["student"],
51
- * hours: 4,
52
- * dayOfWeek: ["monday", "tuesday", "wednesday", "thursday", "friday"],
53
- * priority: "MANDATORY",
54
- * });
55
- * ```
34
+ * @category Rules
56
35
  */
57
- export function createMaxHoursDayRule(config: MaxHoursDayConfig): CompilationRule {
58
- const parsed = MaxHoursDaySchema.parse(config);
59
- const entityScopeValue = parseEntityScope(parsed);
60
- const timeScopeValue = parseTimeScope(parsed);
61
- const { hours, priority } = parsed;
62
- const maxMinutes = hours * 60;
63
- const group = ruleGroup(
64
- `max-hours-day:${hours}`,
65
- `Max ${hours}h per day`,
66
- entityScopeValue,
67
- timeScopeValue,
68
- );
69
-
70
- return {
71
- compile(b) {
72
- const targetMembers = resolveMembersFromScope(entityScopeValue, b.members);
73
- const activeDays = resolveActiveDaysFromScope(timeScopeValue, b.days);
74
-
75
- if (targetMembers.length === 0 || activeDays.length === 0) return;
36
+ export const maxHoursDayRuleDescriptor = defineRuleDescriptor({
37
+ name: "max-hours-day",
38
+ schema: MaxHoursDaySchema,
39
+ compile(config, ctx) {
40
+ const entityScopeValue = parseEntityScope(config);
41
+ const timeScopeValue = parseTimeScope(config);
42
+ const { hours, priority } = config;
43
+ const maxMinutes = hours * 60;
44
+ const group = ruleGroup(
45
+ `max-hours-day:${hours}`,
46
+ `Max ${hours}h per day`,
47
+ entityScopeValue,
48
+ timeScopeValue,
49
+ );
50
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
51
+ const activeDays = resolveActiveDaysFromScope(timeScopeValue, [...ctx.days]);
76
52
 
77
- for (const emp of targetMembers) {
78
- for (const day of activeDays) {
79
- const terms: Term[] = [];
80
- for (const pattern of b.shiftPatterns) {
81
- if (!b.canAssign(emp, pattern)) continue;
82
- if (!b.patternAvailableOnDay(pattern, day)) continue;
83
- terms.push({
84
- var: b.assignment(emp.id, pattern.id, day),
85
- coeff: b.patternDuration(pattern.id),
86
- });
87
- }
53
+ const artifacts = targetMembers.flatMap((member) =>
54
+ activeDays.flatMap((day) => {
55
+ const terms = assignmentTermsForDay(member, day, ctx.shiftPatterns, patternDurationMinutes);
56
+ if (terms.length === 0) return [];
88
57
 
89
- if (terms.length === 0) continue;
58
+ const description = `${member.id} max ${hours}h on ${day.iso}`;
59
+ const context = { memberIds: [member.id], days: [day.iso] };
60
+ const constraintId = `max-hours-day:${member.id}:${day.iso}`;
90
61
 
91
- const constraintId = `max-hours-day:${emp.id}:${day}`;
62
+ return [
63
+ priority === "MANDATORY"
64
+ ? hardConstraint({
65
+ group,
66
+ description,
67
+ context,
68
+ validation: reportValidation(constraintId),
69
+ terms,
70
+ comparator: "<=",
71
+ targetValue: maxMinutes,
72
+ })
73
+ : softConstraint({
74
+ group,
75
+ description,
76
+ context,
77
+ validation: reportValidation(),
78
+ terms,
79
+ comparator: "<=",
80
+ targetValue: maxMinutes,
81
+ penalty: priorityToPenalty(priority),
82
+ constraintId,
83
+ }),
84
+ ];
85
+ }),
86
+ );
92
87
 
93
- if (priority === "MANDATORY") {
94
- b.addLinear(terms, "<=", maxMinutes);
95
- } else {
96
- b.addSoftLinear(terms, "<=", maxMinutes, priorityToPenalty(priority), constraintId);
97
- b.reporter.trackConstraint({
98
- id: constraintId,
99
- type: "rule",
100
- rule: "max-hours-day",
101
- description: `${emp.id} max ${hours}h on ${day}`,
102
- targetValue: maxMinutes,
103
- comparator: "<=",
104
- day,
105
- context: { memberIds: [emp.id], days: [day] },
106
- group,
107
- });
108
- }
109
- }
110
- }
111
- },
112
- };
113
- }
88
+ return {
89
+ rule: "max-hours-day",
90
+ artifacts,
91
+ };
92
+ },
93
+ });