Spaces:
Running
Running
Upload 8 files
Browse files- astronomy_events_registry.json +21 -20
- fiqh_time_registry.json +696 -704
- hijri_calendar_engine.js +69 -79
- hijri_calendar_registry.json +21 -0
- solar_engine.js +65 -90
- validate_registries.js +61 -77
- worship_event_engine.js +24 -23
- worship_fiqh_registry.json +636 -603
astronomy_events_registry.json
CHANGED
|
@@ -14,7 +14,14 @@
|
|
| 14 |
"dismiss_behavior": "current_trigger_only",
|
| 15 |
"completion_tracking": false,
|
| 16 |
"max_popup_per_event_phase": 1,
|
| 17 |
-
"image_fallback": "assets/astronomy/default_space.webp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
},
|
| 19 |
"source_strategy": {
|
| 20 |
"primary_engine": {
|
|
@@ -67,7 +74,8 @@
|
|
| 67 |
"peak",
|
| 68 |
"end"
|
| 69 |
],
|
| 70 |
-
"match": "any"
|
|
|
|
| 71 |
},
|
| 72 |
"fiqh_note": "نافذة الصلاة وحكم وقتها (ومنه علاقتها بأوقات النهي) تُقرأ من fiqh_time_registry/worship_fiqh_registry لا من هذا الملف"
|
| 73 |
},
|
|
@@ -150,7 +158,8 @@
|
|
| 150 |
"peak",
|
| 151 |
"end"
|
| 152 |
],
|
| 153 |
-
"match": "any"
|
|
|
|
| 154 |
},
|
| 155 |
"fiqh_note": "نافذة الصلاة وحكم وقتها تُقرأ من fiqh_time_registry/worship_fiqh_registry لا من هذا الملف"
|
| 156 |
},
|
|
@@ -314,15 +323,16 @@
|
|
| 314 |
"triggers": [
|
| 315 |
{
|
| 316 |
"id": "sunset_check",
|
| 317 |
-
"when": "
|
| 318 |
-
"
|
| 319 |
-
"hijri_day_in": [
|
| 320 |
-
29,
|
| 321 |
-
30
|
| 322 |
-
],
|
| 323 |
-
"at": {
|
| 324 |
"event": "maghrib",
|
| 325 |
"offset_minutes": 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
}
|
| 327 |
}
|
| 328 |
],
|
|
@@ -586,8 +596,7 @@
|
|
| 586 |
"v1_1: توحيد last_quarter مع محرك المحاكاة (كان third_quarter)",
|
| 587 |
"v1_1: category_controls: الكسوف والخسوف دائمًا فعّالان، وبقية الفئات يستطيع المستخدم إيقافها",
|
| 588 |
"v1_1: إضافة crescent_visibility وmoonrise_moonset",
|
| 589 |
-
"v1_2: ت
|
| 590 |
-
"v1_2: engine_limits: أرقام البحث عن الكسوف والخسوف انتقلت من worship_event_engine.js"
|
| 591 |
],
|
| 592 |
"category_controls": {
|
| 593 |
"note": "الكسوف والخسوف دائمًا فعّالان لارتباطهما بعبادة. الفئات الأخرى معلومات يستطيع المستخدم إيقافها.",
|
|
@@ -606,13 +615,5 @@
|
|
| 606 |
"planetary": {
|
| 607 |
"user_can_disable": true
|
| 608 |
}
|
| 609 |
-
},
|
| 610 |
-
"engine_limits": {
|
| 611 |
-
"eclipse_lookback_days": 1,
|
| 612 |
-
"eclipse_peak_lookahead_days": 1,
|
| 613 |
-
"eclipse_max_occurrences": 8,
|
| 614 |
-
"eclipse_cache_entries": 4,
|
| 615 |
-
"visibility_epsilon_ms": 1000,
|
| 616 |
-
"default_visibility_min_altitude_deg": 0
|
| 617 |
}
|
| 618 |
}
|
|
|
|
| 14 |
"dismiss_behavior": "current_trigger_only",
|
| 15 |
"completion_tracking": false,
|
| 16 |
"max_popup_per_event_phase": 1,
|
| 17 |
+
"image_fallback": "assets/astronomy/default_space.webp",
|
| 18 |
+
"eclipse_scan": {
|
| 19 |
+
"note": "حدود بحث الكسوف والخسوف في worship_event_engine. لا قيم افتراضية داخل الكود.",
|
| 20 |
+
"max_occurrences": 8,
|
| 21 |
+
"lookback_days": 1,
|
| 22 |
+
"cache_limit": 4,
|
| 23 |
+
"epsilon_ms": 1000
|
| 24 |
+
}
|
| 25 |
},
|
| 26 |
"source_strategy": {
|
| 27 |
"primary_engine": {
|
|
|
|
| 74 |
"peak",
|
| 75 |
"end"
|
| 76 |
],
|
| 77 |
+
"match": "any",
|
| 78 |
+
"altitude_reference": "geometric_center"
|
| 79 |
},
|
| 80 |
"fiqh_note": "نافذة الصلاة وحكم وقتها (ومنه علاقتها بأوقات النهي) تُقرأ من fiqh_time_registry/worship_fiqh_registry لا من هذا الملف"
|
| 81 |
},
|
|
|
|
| 158 |
"peak",
|
| 159 |
"end"
|
| 160 |
],
|
| 161 |
+
"match": "any",
|
| 162 |
+
"altitude_reference": "geometric_center"
|
| 163 |
},
|
| 164 |
"fiqh_note": "نافذة الصلاة وحكم وقتها تُقرأ من fiqh_time_registry/worship_fiqh_registry لا من هذا الملف"
|
| 165 |
},
|
|
|
|
| 323 |
"triggers": [
|
| 324 |
{
|
| 325 |
"id": "sunset_check",
|
| 326 |
+
"when": "anchor",
|
| 327 |
+
"anchor": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
"event": "maghrib",
|
| 329 |
"offset_minutes": 0
|
| 330 |
+
},
|
| 331 |
+
"condition": {
|
| 332 |
+
"hijri_day_in": [
|
| 333 |
+
29,
|
| 334 |
+
30
|
| 335 |
+
]
|
| 336 |
}
|
| 337 |
}
|
| 338 |
],
|
|
|
|
| 596 |
"v1_1: توحيد last_quarter مع محرك المحاكاة (كان third_quarter)",
|
| 597 |
"v1_1: category_controls: الكسوف والخسوف دائمًا فعّالان، وبقية الفئات يستطيع المستخدم إيقافها",
|
| 598 |
"v1_1: إضافة crescent_visibility وmoonrise_moonset",
|
| 599 |
+
"v1_2: defaults.eclipse_scan (كانت أرقام داخل المحرك)، وتوحيد مرجع الارتفاع geometric_center مع Astronomy.SearchAltitude"
|
|
|
|
| 600 |
],
|
| 601 |
"category_controls": {
|
| 602 |
"note": "الكسوف والخسوف دائمًا فعّالان لارتباطهما بعبادة. الفئات الأخرى معلومات يستطيع المستخدم إيقافها.",
|
|
|
|
| 615 |
"planetary": {
|
| 616 |
"user_can_disable": true
|
| 617 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 618 |
}
|
| 619 |
}
|
fiqh_time_registry.json
CHANGED
|
@@ -1,725 +1,717 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
},
|
| 48 |
-
"prayer_engine": {
|
| 49 |
-
"role": "إعطاء أوقات الصلاة المعتمدة حسب إعدادات التطبيق"
|
| 50 |
-
},
|
| 51 |
-
"derived_time_engine": {
|
| 52 |
-
"role": "اشتقاق الحدود الزمنية المركبة من حدود محسوبة أخرى"
|
| 53 |
-
},
|
| 54 |
-
"fiqh_profile": {
|
| 55 |
-
"role": "اختيار الحد الفقهي عندما توجد أكثر من طريقة معتبرة لتفسير حد زمني",
|
| 56 |
-
"note": "هذا الملف يعرّف الزمن فقط؛ الحكم التعبدي يوضع في Registry مستقل."
|
| 57 |
-
}
|
| 58 |
},
|
| 59 |
-
"
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
],
|
| 227 |
-
"
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
"id": "night",
|
| 254 |
-
"start": "sunset",
|
| 255 |
-
"end": "next_true_dawn",
|
| 256 |
-
"semantic": "الفترة الليلية المستخدمة للاشتقاقات الزمنية"
|
| 257 |
-
},
|
| 258 |
-
{
|
| 259 |
-
"id": "first_third_of_night_window",
|
| 260 |
-
"start": "sunset",
|
| 261 |
-
"end": "first_third_of_night",
|
| 262 |
-
"semantic": "نافذة حسابية فقط؛ الحكم الفقهي خارج هذا الملف."
|
| 263 |
-
},
|
| 264 |
-
{
|
| 265 |
-
"id": "last_third_of_night_window",
|
| 266 |
-
"start": "last_third_start",
|
| 267 |
-
"end": "next_true_dawn",
|
| 268 |
-
"semantic": "نافذة حسابية فقط؛ الحكم والعبادة خارج هذا الملف."
|
| 269 |
-
}
|
| 270 |
],
|
| 271 |
-
"
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
"
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
"
|
| 281 |
-
"
|
| 282 |
-
"
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
"
|
| 286 |
-
"
|
| 287 |
-
"
|
| 288 |
-
|
| 289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
"last_third_start",
|
| 291 |
-
"next_false_dawn",
|
| 292 |
"next_true_dawn"
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
"
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
"
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
"role_ar": "هذا الملف يحسب الحدود فقط، وملف worship_fiqh_registry.json يختار أي حد تستخدمه العبادة بحسب المذهب.",
|
| 309 |
-
"madhhab_sensitive_outputs": [
|
| 310 |
-
"asr_shadow_1",
|
| 311 |
-
"asr_shadow_2",
|
| 312 |
-
"first_third_of_night",
|
| 313 |
-
"red_twilight_end",
|
| 314 |
-
"white_twilight_end"
|
| 315 |
-
]
|
| 316 |
-
},
|
| 317 |
-
"calculation_profile": {
|
| 318 |
-
"id": "inherited_solar_estimates_v1",
|
| 319 |
-
"label_ar": "إعدادات شمسية تقديرية من النسخة القديمة",
|
| 320 |
-
"note_ar": "حساب شمسي تقديري يتغير بالموقع والتاريخ. ارتفاع الشمس 4.5° والشفق 15°/18° إعدادات تقديرية موروثة تحتاج اعتمادًا. الاستواء والزوال حدّا انتقال اتجاه حركة الشمس، دون افتراض فترة بالدقائق؛ هذه ليست مواقيت أذان رسمية.",
|
| 321 |
-
"provenance": {
|
| 322 |
-
"solar_geometry": "index-8.html: sunPosition / solarAltitudeAt",
|
| 323 |
-
"sunrise_clear": "index-8.html: solarFiqhBoundaries, 4.5 degrees",
|
| 324 |
-
"zawal": "fiqh_time_registry_solar_v1_1.json: post_transit_transition / after_upper_solar_transit؛ حل عددي لتغير اتجاه الارتفاع بعد القمة، دون مساواة alias أو عتبة انخفاض مخترعة.",
|
| 325 |
-
"sunset_approach": "index-8.html: estimateSunsetStart, -0.30 degrees",
|
| 326 |
-
"twilight": "spiritual_timeline_v3_fiqh_timers_FINAL.zip: fiqh_time_registry.json, red 15 and white 18 degrees",
|
| 327 |
-
"true_dawn": "index-8.html: FAJR_ANGLE = 18"
|
| 328 |
-
},
|
| 329 |
-
"default_madhhab": "shafii",
|
| 330 |
-
"locations": [
|
| 331 |
-
{
|
| 332 |
-
"name": "عمّان",
|
| 333 |
-
"lat": 31.9454,
|
| 334 |
-
"lng": 35.9284,
|
| 335 |
-
"timezone": "Asia/Amman",
|
| 336 |
-
"height": 0
|
| 337 |
-
}
|
| 338 |
-
],
|
| 339 |
-
"observational_limits": {
|
| 340 |
-
"false_dawn": null,
|
| 341 |
-
"next_false_dawn": null
|
| 342 |
-
},
|
| 343 |
-
"boundaries": {
|
| 344 |
-
"false_dawn": {
|
| 345 |
-
"op": "altitude",
|
| 346 |
-
"degrees": -20,
|
| 347 |
-
"direction": "ascending",
|
| 348 |
-
"approximate": true,
|
| 349 |
-
"provisional": true,
|
| 350 |
-
"note_ar": "قيمة مؤقتة لتفعيل مرساة الدورة اليومية فقط، وهي رصدية تقديرية. تحتاج اعتماد المرجع الفلكي قبل الاعتماد النهائي، ولا تدخل في حساب أي عبادة."
|
| 351 |
-
},
|
| 352 |
-
"solar_noon": {
|
| 353 |
-
"op": "maximum"
|
| 354 |
-
},
|
| 355 |
-
"true_dawn": {
|
| 356 |
-
"op": "altitude",
|
| 357 |
-
"degrees": -18,
|
| 358 |
-
"direction": "ascending"
|
| 359 |
-
},
|
| 360 |
-
"sunrise": {
|
| 361 |
-
"op": "altitude",
|
| 362 |
-
"degrees": -0.833,
|
| 363 |
-
"direction": "ascending"
|
| 364 |
-
},
|
| 365 |
-
"sunrise_clear": {
|
| 366 |
-
"op": "altitude",
|
| 367 |
-
"degrees": 4.5,
|
| 368 |
-
"direction": "ascending",
|
| 369 |
-
"approximate": true
|
| 370 |
-
},
|
| 371 |
-
"zawal": {
|
| 372 |
-
"op": "post_transit_transition",
|
| 373 |
-
"boundary": "solar_noon",
|
| 374 |
-
"direction": "descending",
|
| 375 |
-
"transition_only": true,
|
| 376 |
-
"note_ar": "الزوال محسوب من بدء انخفاض ارتفاع الشمس بعد الاستواء. يعرض كحد شمسي؛ لا يستنتج الحساب منه فترة نهي ممتدة بالدقائق."
|
| 377 |
-
},
|
| 378 |
-
"sunset_approach": {
|
| 379 |
-
"op": "altitude",
|
| 380 |
-
"degrees": -0.3,
|
| 381 |
-
"direction": "descending",
|
| 382 |
-
"approximate": true
|
| 383 |
-
},
|
| 384 |
-
"sunset": {
|
| 385 |
-
"op": "altitude",
|
| 386 |
-
"degrees": -0.833,
|
| 387 |
-
"direction": "descending"
|
| 388 |
-
},
|
| 389 |
-
"red_twilight_end": {
|
| 390 |
-
"op": "altitude",
|
| 391 |
-
"degrees": -15,
|
| 392 |
-
"direction": "descending",
|
| 393 |
-
"approximate": true
|
| 394 |
-
},
|
| 395 |
-
"white_twilight_end": {
|
| 396 |
-
"op": "altitude",
|
| 397 |
-
"degrees": -18,
|
| 398 |
-
"direction": "descending",
|
| 399 |
-
"approximate": true
|
| 400 |
-
},
|
| 401 |
-
"asr_shadow_1": {
|
| 402 |
-
"op": "shadow",
|
| 403 |
-
"factor": 1
|
| 404 |
-
},
|
| 405 |
-
"asr_shadow_2": {
|
| 406 |
-
"op": "shadow",
|
| 407 |
-
"factor": 2
|
| 408 |
-
},
|
| 409 |
-
"fajr": {
|
| 410 |
-
"op": "alias",
|
| 411 |
-
"boundary": "true_dawn"
|
| 412 |
-
},
|
| 413 |
-
"dhuhr": {
|
| 414 |
-
"op": "alias",
|
| 415 |
-
"boundary": "zawal"
|
| 416 |
-
},
|
| 417 |
-
"maghrib": {
|
| 418 |
-
"op": "alias",
|
| 419 |
-
"boundary": "sunset"
|
| 420 |
-
},
|
| 421 |
-
"asr": {
|
| 422 |
-
"op": "rule_start",
|
| 423 |
-
"rule_id": "asr"
|
| 424 |
-
},
|
| 425 |
-
"isha": {
|
| 426 |
-
"op": "rule_start",
|
| 427 |
-
"rule_id": "isha_entry"
|
| 428 |
-
},
|
| 429 |
-
"isha_entry_hanafi": {
|
| 430 |
-
"op": "alias",
|
| 431 |
-
"boundary": "white_twilight_end"
|
| 432 |
-
},
|
| 433 |
-
"next_true_dawn": {
|
| 434 |
-
"op": "next_day",
|
| 435 |
-
"boundary": "true_dawn"
|
| 436 |
-
},
|
| 437 |
-
"first_third_of_night": {
|
| 438 |
-
"op": "fraction",
|
| 439 |
-
"from": "sunset",
|
| 440 |
-
"to": "next_true_dawn",
|
| 441 |
-
"fraction": 0.3333333333333333
|
| 442 |
-
},
|
| 443 |
-
"islamic_midnight": {
|
| 444 |
-
"op": "fraction",
|
| 445 |
-
"from": "sunset",
|
| 446 |
-
"to": "next_true_dawn",
|
| 447 |
-
"fraction": 0.5
|
| 448 |
-
},
|
| 449 |
-
"last_third_start": {
|
| 450 |
-
"op": "fraction",
|
| 451 |
-
"from": "sunset",
|
| 452 |
-
"to": "next_true_dawn",
|
| 453 |
-
"fraction": 0.6666666666666666
|
| 454 |
-
},
|
| 455 |
-
"next_false_dawn": {
|
| 456 |
-
"op": "next_day",
|
| 457 |
-
"boundary": "false_dawn"
|
| 458 |
-
}
|
| 459 |
},
|
| 460 |
-
"
|
| 461 |
-
|
| 462 |
-
"last_third_start_to_next_true_dawn": [
|
| 463 |
-
"last_third_start",
|
| 464 |
-
"next_true_dawn"
|
| 465 |
-
]
|
| 466 |
},
|
| 467 |
-
"
|
| 468 |
-
|
| 469 |
-
"end": "next_true_dawn"
|
| 470 |
-
},
|
| 471 |
-
"isha_periods": {
|
| 472 |
-
"start": "isha"
|
| 473 |
-
}
|
| 474 |
},
|
| 475 |
-
"
|
| 476 |
-
|
| 477 |
-
"trigger_bindings": {
|
| 478 |
-
"day_start": {
|
| 479 |
-
"boundary": "true_dawn"
|
| 480 |
-
},
|
| 481 |
-
"after_fajr": {
|
| 482 |
-
"boundary": "fajr"
|
| 483 |
-
},
|
| 484 |
-
"after_dhuhr": {
|
| 485 |
-
"boundary": "dhuhr"
|
| 486 |
-
},
|
| 487 |
-
"after_asr": {
|
| 488 |
-
"boundary": "asr"
|
| 489 |
-
},
|
| 490 |
-
"after_maghrib": {
|
| 491 |
-
"boundary": "maghrib"
|
| 492 |
-
},
|
| 493 |
-
"after_isha": {
|
| 494 |
-
"boundary": "isha"
|
| 495 |
-
},
|
| 496 |
-
"before_fajr": {
|
| 497 |
-
"boundary": "fajr",
|
| 498 |
-
"offset_sign": -1
|
| 499 |
-
},
|
| 500 |
-
"before_jumuah": {
|
| 501 |
-
"boundary": "dhuhr",
|
| 502 |
-
"offset_sign": -1
|
| 503 |
-
},
|
| 504 |
-
"duha_start": {
|
| 505 |
-
"boundary": "sunrise_clear"
|
| 506 |
-
},
|
| 507 |
-
"last_third_start": {
|
| 508 |
-
"boundary": "last_third_start"
|
| 509 |
-
},
|
| 510 |
-
"previous_evening": {
|
| 511 |
-
"boundary": "sunset",
|
| 512 |
-
"day_shift": -1
|
| 513 |
-
},
|
| 514 |
-
"sunday_evening": {
|
| 515 |
-
"boundary": "sunset",
|
| 516 |
-
"day_shift": -1
|
| 517 |
-
},
|
| 518 |
-
"wednesday_evening": {
|
| 519 |
-
"boundary": "sunset",
|
| 520 |
-
"day_shift": -1
|
| 521 |
-
}
|
| 522 |
-
},
|
| 523 |
-
"note_ar": "نافذة استدراك التنبيه سياسة تطبيق فقط. حدود أوقات النهي لا تستخدم هذه الإزاحات. التنبيهات تعمل أثناء فتح الصفحة، ويحدّد سجل الحدث عدد مرات ظهوره."
|
| 524 |
},
|
| 525 |
-
"
|
| 526 |
-
|
| 527 |
-
"derivative_sample_ms": 1000,
|
| 528 |
-
"note_ar": "دقة عددية للبحث عن انقلاب اتجاه الارتفاع؛ ليست مدة نهي أو إزاحة زمنية للزوال. جميع القيم العددية للمحرك تأتي من هنا ولا شيء منها مكتوب في solar_engine.js.",
|
| 529 |
-
"scan_step_ms": 300000,
|
| 530 |
-
"bisect_iterations": 36,
|
| 531 |
-
"maximum_iterations": 60,
|
| 532 |
-
"transition_iterations": 80,
|
| 533 |
-
"noon_search_half_window_ms": 21600000,
|
| 534 |
-
"crossing_window_ms": 43200000,
|
| 535 |
-
"alias_passes": 5,
|
| 536 |
-
"use_astronomy_search_functions": true
|
| 537 |
},
|
| 538 |
-
"
|
| 539 |
-
|
| 540 |
-
"algorithm_reference": "Jean Meeus, Astronomical Algorithms",
|
| 541 |
-
"indicator_position_source": "device_clock_on_continuous_timeline",
|
| 542 |
-
"day_night_source": "computed_sunrise_and_sunset",
|
| 543 |
-
"apparent_horizon_degrees": -0.833,
|
| 544 |
-
"uses_prayer_time_provider": false,
|
| 545 |
-
"note_ar": "حركة المؤشر تتبع وقت الجهاز على الخط المتصل، وحالة الشمس/القمر تتبع ارتفاع الشمس المحسوب للموقع. حد الشروق والغروب الظاهري −0.833°؛ وقد يختلف الرصد الفعلي قليلًا بسبب الغلاف الجوي والأفق المحلي."
|
| 546 |
-
}
|
| 547 |
-
},
|
| 548 |
-
"prayer_calculation": {
|
| 549 |
-
"default_method": "JordanAwqaf",
|
| 550 |
-
"storage_key": "clock_calculation_method_v1",
|
| 551 |
-
"legacy_option": {
|
| 552 |
-
"id": "registry",
|
| 553 |
-
"label": "الحدود الشمسية والسجل الفقهي الحالي"
|
| 554 |
},
|
| 555 |
-
"
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
"timeout_ms": 12000,
|
| 559 |
-
"source": "Adhan JS 4.4.6؛ الحسابات الفلكية مبنية على Astronomical Algorithms لِـ Jean Meeus",
|
| 560 |
-
"fallback_url": "vendor/adhan.umd.min.js",
|
| 561 |
-
"offline_note_ar": "يُحمَّل من الرابط أولًا ثم من النسخة المحلية عند فشله؛ ضع الملف بجوار index.html وأضفه إلى ملفات sw.js المخزنة مؤقتًا ليعمل التطبيق دون إنترنت."
|
| 562 |
},
|
| 563 |
-
"
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
"label": "الأردن — وزارة الأوقاف",
|
| 567 |
-
"engine_mode": "custom_angles",
|
| 568 |
-
"fajr_angle": 18,
|
| 569 |
-
"isha_angle": 18,
|
| 570 |
-
"adjustments": {
|
| 571 |
-
"maghrib": 5
|
| 572 |
-
},
|
| 573 |
-
"provider_method_id": 23,
|
| 574 |
-
"solar_sunset_is_independent": true,
|
| 575 |
-
"authority_name": "وزارة الأوقاف والشؤون والمقدسات الإسلامية — الأردن",
|
| 576 |
-
"method_reference_url": "https://api.aladhan.com/v1/methods",
|
| 577 |
-
"daily_reference_url": "https://www.aliftaa.jo/Default",
|
| 578 |
-
"note_ar": "تطبيق محلي لمعاملات طريقة الأردن المنشورة: الفجر 18°، العشاء 18°، والمغرب بعد الغروب بخمس دقائق. تبقى مواقيت دائرة الإفتاء اليومية مرجع المقارنة الرسمي لمدينة عمّان."
|
| 579 |
-
},
|
| 580 |
-
{
|
| 581 |
-
"id": "MuslimWorldLeague",
|
| 582 |
-
"label": "رابطة العالم الإسلامي"
|
| 583 |
-
},
|
| 584 |
-
{
|
| 585 |
-
"id": "UmmAlQura",
|
| 586 |
-
"label": "أم القرى - مكة"
|
| 587 |
-
},
|
| 588 |
-
{
|
| 589 |
-
"id": "Egyptian",
|
| 590 |
-
"label": "الهيئة المصرية للمساحة"
|
| 591 |
-
},
|
| 592 |
-
{
|
| 593 |
-
"id": "Karachi",
|
| 594 |
-
"label": "كراتشي"
|
| 595 |
-
},
|
| 596 |
-
{
|
| 597 |
-
"id": "Dubai",
|
| 598 |
-
"label": "دبي"
|
| 599 |
-
},
|
| 600 |
-
{
|
| 601 |
-
"id": "Qatar",
|
| 602 |
-
"label": "قطر"
|
| 603 |
-
},
|
| 604 |
-
{
|
| 605 |
-
"id": "Kuwait",
|
| 606 |
-
"label": "الكويت"
|
| 607 |
-
},
|
| 608 |
-
{
|
| 609 |
-
"id": "MoonsightingCommittee",
|
| 610 |
-
"label": "لجنة تحري الهلال"
|
| 611 |
-
},
|
| 612 |
-
{
|
| 613 |
-
"id": "Singapore",
|
| 614 |
-
"label": "سنغافورة / ماليزيا / إندونيسيا"
|
| 615 |
-
},
|
| 616 |
-
{
|
| 617 |
-
"id": "Turkey",
|
| 618 |
-
"label": "تركيا"
|
| 619 |
-
},
|
| 620 |
-
{
|
| 621 |
-
"id": "Tehran",
|
| 622 |
-
"label": "طهران"
|
| 623 |
-
},
|
| 624 |
-
{
|
| 625 |
-
"id": "NorthAmerica",
|
| 626 |
-
"label": "ISNA - أمريكا الشمالية"
|
| 627 |
-
}
|
| 628 |
-
],
|
| 629 |
-
"shadow_factor_to_madhab": {
|
| 630 |
-
"1": "Shafi",
|
| 631 |
-
"2": "Hanafi"
|
| 632 |
},
|
| 633 |
-
"
|
| 634 |
-
|
| 635 |
-
"asr_shadow_factor": 2,
|
| 636 |
-
"adhan_madhab": "Hanafi",
|
| 637 |
-
"moonsighting_shafaq": "Abyad"
|
| 638 |
-
},
|
| 639 |
-
"maliki": {
|
| 640 |
-
"asr_shadow_factor": 1,
|
| 641 |
-
"adhan_madhab": "Shafi",
|
| 642 |
-
"moonsighting_shafaq": "Ahmer"
|
| 643 |
-
},
|
| 644 |
-
"shafii": {
|
| 645 |
-
"asr_shadow_factor": 1,
|
| 646 |
-
"adhan_madhab": "Shafi",
|
| 647 |
-
"moonsighting_shafaq": "Ahmer"
|
| 648 |
-
},
|
| 649 |
-
"hanbali": {
|
| 650 |
-
"asr_shadow_factor": 1,
|
| 651 |
-
"adhan_madhab": "Shafi",
|
| 652 |
-
"moonsighting_shafaq": "Ahmer"
|
| 653 |
-
}
|
| 654 |
},
|
| 655 |
-
"
|
| 656 |
-
|
| 657 |
-
"dhuhr": "dhuhr",
|
| 658 |
-
"asr": "asr",
|
| 659 |
-
"maghrib": "maghrib",
|
| 660 |
-
"isha": "isha"
|
| 661 |
},
|
| 662 |
-
"
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
"end": "sunrise"
|
| 666 |
-
},
|
| 667 |
-
"dhuhr": {
|
| 668 |
-
"start": "dhuhr",
|
| 669 |
-
"end": "asr"
|
| 670 |
-
},
|
| 671 |
-
"asr": {
|
| 672 |
-
"start": "asr",
|
| 673 |
-
"end": "maghrib"
|
| 674 |
-
},
|
| 675 |
-
"maghrib": {
|
| 676 |
-
"start": "maghrib",
|
| 677 |
-
"end": "isha"
|
| 678 |
-
},
|
| 679 |
-
"isha_entry": {
|
| 680 |
-
"start": "isha",
|
| 681 |
-
"end": "next_true_dawn"
|
| 682 |
-
}
|
| 683 |
},
|
| 684 |
-
"
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
"storage_key": "clock_ummalqura_ramadan_v1"
|
| 688 |
},
|
| 689 |
-
"
|
| 690 |
-
|
| 691 |
-
|
| 692 |
-
"storage_key": "clock_high_latitude_rule_v1",
|
| 693 |
-
"options": [
|
| 694 |
-
{
|
| 695 |
-
"id": "recommended",
|
| 696 |
-
"label_ar": "الموصى به حسب خط العرض",
|
| 697 |
-
"adhan": "HighLatitudeRule.recommended"
|
| 698 |
-
},
|
| 699 |
-
{
|
| 700 |
-
"id": "MiddleOfTheNight",
|
| 701 |
-
"label_ar": "منتصف الليل",
|
| 702 |
-
"adhan": "HighLatitudeRule.MiddleOfTheNight"
|
| 703 |
-
},
|
| 704 |
-
{
|
| 705 |
-
"id": "SeventhOfTheNight",
|
| 706 |
-
"label_ar": "سُبع الليل",
|
| 707 |
-
"adhan": "HighLatitudeRule.SeventhOfTheNight"
|
| 708 |
-
},
|
| 709 |
-
{
|
| 710 |
-
"id": "TwilightAngle",
|
| 711 |
-
"label_ar": "زاوية الشفق",
|
| 712 |
-
"adhan": "HighLatitudeRule.TwilightAngle"
|
| 713 |
-
}
|
| 714 |
-
],
|
| 715 |
-
"note_ar": "في المناطق التي لا يغيب فيها الشفق أو لا تغرب فيها الشمس يخفق حساب الزاوية، فتُستخدم هذه القاعدة. يتحقق المطوّر من وجود recommended في إصدار Adhan المثبت. الحدود الشمسية المستقلة تعرض سبب التعذر في unavailable بدل قيمة وهمية."
|
| 716 |
}
|
|
|
|
|
|
|
| 717 |
},
|
| 718 |
-
"
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 725 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"schema_name": "islamic_clock_fiqh_time_registry",
|
| 3 |
+
"schema_version": "1.6.0",
|
| 4 |
+
"registry_id": "fiqh_time_registry",
|
| 5 |
+
"project": "الساعة الإسلامية / الخط الزمني الروحي",
|
| 6 |
+
"language": "ar",
|
| 7 |
+
"rtl": true,
|
| 8 |
+
"status": "time_boundaries_registry",
|
| 9 |
+
"purpose": "تعريف محطات وحدود الزمن التي تعتمد عليها المسطرة. لا يحتوي هذا الملف على ألوان أو أحكام عبادات أو محتوى.",
|
| 10 |
+
"separation_contract": {
|
| 11 |
+
"this_registry_owns": [
|
| 12 |
+
"أسماء الحدود الزمنية",
|
| 13 |
+
"ترتيب الحدود في الدورة اليومية",
|
| 14 |
+
"نوع مصدر كل حد: فلكي أو محرك صلاة أو مشتق",
|
| 15 |
+
"علاقات البداية والنهاية بين الحدود"
|
| 16 |
+
],
|
| 17 |
+
"this_registry_does_not_own": [
|
| 18 |
+
"ألوان المسطرة",
|
| 19 |
+
"حكم النهي أو الاستحباب",
|
| 20 |
+
"محتوى العبادات",
|
| 21 |
+
"النوافذ المنبثقة",
|
| 22 |
+
"تسجيل إنجاز العبادات"
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
"clock_display": {
|
| 26 |
+
"format": "12_hour",
|
| 27 |
+
"arabic_dayparts": true,
|
| 28 |
+
"examples": [
|
| 29 |
+
"6:00 صباحًا",
|
| 30 |
+
"12:00 ظهرًا",
|
| 31 |
+
"4:00 مساءً",
|
| 32 |
+
"12:00 منتصف الليل"
|
| 33 |
+
],
|
| 34 |
+
"forbid_24_hour_labels_in_ui": true
|
| 35 |
+
},
|
| 36 |
+
"daily_cycle": {
|
| 37 |
+
"anchor": "false_dawn",
|
| 38 |
+
"continues_into_next_day": true,
|
| 39 |
+
"end_boundary": "next_false_dawn",
|
| 40 |
+
"ui_model": "continuous_horizontal_ruler",
|
| 41 |
+
"note": "الدورة الزمنية متصلة؛ الوصول إلى نهاية الدورة يدخل مباشرة في دورة اليوم التالي."
|
| 42 |
+
},
|
| 43 |
+
"authorities": {
|
| 44 |
+
"astronomy_engine": {
|
| 45 |
+
"role": "حساب موضع الشمس والحدود الفلكية والرصدية",
|
| 46 |
+
"hardcoded_clock_minutes_for_solar_boundaries": false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
},
|
| 48 |
+
"prayer_engine": {
|
| 49 |
+
"role": "إعطاء أوقات الصلاة المعتمدة حسب إعدادات التطبيق"
|
| 50 |
+
},
|
| 51 |
+
"derived_time_engine": {
|
| 52 |
+
"role": "اشتقاق الحدود الزمنية المركبة من حدود محسوبة أخرى"
|
| 53 |
+
},
|
| 54 |
+
"fiqh_profile": {
|
| 55 |
+
"role": "اختيار الحد الفقهي عندما توجد أكثر من طريقة معتبرة لتفسير حد زمني",
|
| 56 |
+
"note": "هذا الملف يعرّف الزمن فقط؛ الحكم التعبدي يوضع في Registry مستقل."
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
"boundaries": [
|
| 60 |
+
{
|
| 61 |
+
"id": "false_dawn",
|
| 62 |
+
"label": "الفجر الكاذب",
|
| 63 |
+
"source": "astronomy_engine",
|
| 64 |
+
"kind": "observational_estimate",
|
| 65 |
+
"fixed_minutes": false,
|
| 66 |
+
"note": "حد رصدي/فلكي تقديري مستقل عن الفجر الصادق."
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
"id": "true_dawn",
|
| 70 |
+
"label": "الفجر الصادق",
|
| 71 |
+
"source": "prayer_engine",
|
| 72 |
+
"kind": "prayer_boundary",
|
| 73 |
+
"fixed_minutes": false
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"id": "sunrise",
|
| 77 |
+
"label": "الشروق",
|
| 78 |
+
"source": "astronomy_engine",
|
| 79 |
+
"kind": "solar_boundary",
|
| 80 |
+
"fixed_minutes": false
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"id": "sunrise_clear",
|
| 84 |
+
"label": "ارتفاع الشمس بعد الشروق",
|
| 85 |
+
"source": "astronomy_engine",
|
| 86 |
+
"kind": "solar_boundary",
|
| 87 |
+
"fixed_minutes": false,
|
| 88 |
+
"note": "يحسب من حركة الشمس؛ لا يُختزل في عدد دقائق ثابت بعد الشروق."
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"id": "solar_noon",
|
| 92 |
+
"label": "الاستواء الشمسي",
|
| 93 |
+
"source": "astronomy_engine",
|
| 94 |
+
"kind": "solar_boundary",
|
| 95 |
+
"fixed_minutes": false
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"id": "zawal",
|
| 99 |
+
"label": "الزوال",
|
| 100 |
+
"source": "astronomy_engine",
|
| 101 |
+
"kind": "solar_transition",
|
| 102 |
+
"fixed_minutes": false,
|
| 103 |
+
"relation": "بعد الاستواء عندما تبدأ الشمس بالميل عن أعلى ارتفاع"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"id": "dhuhr",
|
| 107 |
+
"label": "الظهر",
|
| 108 |
+
"source": "prayer_engine",
|
| 109 |
+
"kind": "prayer_boundary",
|
| 110 |
+
"fixed_minutes": false
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"id": "asr_shadow_1",
|
| 114 |
+
"label": "حد الظل: المثل",
|
| 115 |
+
"source": "astronomy_engine",
|
| 116 |
+
"kind": "shadow_factor_boundary",
|
| 117 |
+
"shadow_factor": 1,
|
| 118 |
+
"exclude_noon_shadow": true,
|
| 119 |
+
"fixed_minutes": false,
|
| 120 |
+
"note": "يحسب من طول الظل بعد استبعاد فيء الزوال؛ يستخدمه ملف الفقه لبدء العصر عند الجمهور وبعض الأقوال الحنفية."
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"id": "asr_shadow_2",
|
| 124 |
+
"label": "حد الظل: المثلان",
|
| 125 |
+
"source": "astronomy_engine",
|
| 126 |
+
"kind": "shadow_factor_boundary",
|
| 127 |
+
"shadow_factor": 2,
|
| 128 |
+
"exclude_noon_shadow": true,
|
| 129 |
+
"fixed_minutes": false,
|
| 130 |
+
"note": "يحسب من طول الظل بعد استبعاد فيء الزوال؛ يستخدمه ملف الفقه لقول أبي حنيفة المشهور في بدء العصر."
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"id": "asr",
|
| 134 |
+
"label": "العصر",
|
| 135 |
+
"source": "prayer_engine",
|
| 136 |
+
"kind": "prayer_boundary",
|
| 137 |
+
"fixed_minutes": false
|
| 138 |
+
},
|
| 139 |
+
{
|
| 140 |
+
"id": "last_daylight_hour_start",
|
| 141 |
+
"label": "بداية آخر جزء من النهار",
|
| 142 |
+
"source": "derived_time_engine",
|
| 143 |
+
"kind": "derived_boundary",
|
| 144 |
+
"formula": "sunrise + (11/12 * duration(sunrise, sunset))",
|
| 145 |
+
"fixed_minutes": false,
|
| 146 |
+
"note": "النهار اثنا عشر جزءًا متساويًا بين الشروق والغروب؛ الحد حسابي فقط وتستخدمه طبقة الفقه لعرض ساعة الإجابة."
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"id": "sunset_approach",
|
| 150 |
+
"label": "اقتراب الغروب",
|
| 151 |
+
"source": "astronomy_engine",
|
| 152 |
+
"kind": "solar_boundary",
|
| 153 |
+
"fixed_minutes": false,
|
| 154 |
+
"note": "لا يساوي وقت العصر ولا يُحدد برقم ساعة ثابت."
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"id": "sunset",
|
| 158 |
+
"label": "الغروب",
|
| 159 |
+
"source": "astronomy_engine",
|
| 160 |
+
"kind": "solar_boundary",
|
| 161 |
+
"fixed_minutes": false
|
| 162 |
+
},
|
| 163 |
+
{
|
| 164 |
+
"id": "maghrib",
|
| 165 |
+
"label": "المغرب",
|
| 166 |
+
"source": "prayer_engine",
|
| 167 |
+
"kind": "prayer_boundary",
|
| 168 |
+
"fixed_minutes": false
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"id": "red_twilight_end",
|
| 172 |
+
"label": "نهاية الشفق الأحمر",
|
| 173 |
+
"source": "astronomy_engine",
|
| 174 |
+
"kind": "observational_estimate",
|
| 175 |
+
"fixed_minutes": false,
|
| 176 |
+
"note": "حد رصدي تقديري مستقل عن حد دخول العشاء الفقهي."
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"id": "white_twilight_end",
|
| 180 |
+
"label": "نهاية الشفق الأبيض",
|
| 181 |
+
"source": "astronomy_engine",
|
| 182 |
+
"kind": "observational_estimate",
|
| 183 |
+
"fixed_minutes": false,
|
| 184 |
+
"note": "حد رصدي تقديري مستقل عن حد دخول العشاء الفقهي."
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"id": "isha",
|
| 188 |
+
"label": "العشاء",
|
| 189 |
+
"source": "prayer_engine",
|
| 190 |
+
"kind": "prayer_boundary",
|
| 191 |
+
"fixed_minutes": false
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"id": "first_third_of_night",
|
| 195 |
+
"label": "نهاية الثلث الأول من الليل",
|
| 196 |
+
"source": "derived_time_engine",
|
| 197 |
+
"kind": "derived_boundary",
|
| 198 |
+
"formula": "sunset + (1/3 * duration(sunset, next_true_dawn))",
|
| 199 |
+
"fixed_minutes": false,
|
| 200 |
+
"note": "حد حسابي فقط تستخدمه طبقة الفقه عند تمييز فترات العشاء."
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"id": "islamic_midnight",
|
| 204 |
+
"label": "منتصف الليل الشرعي",
|
| 205 |
+
"source": "derived_time_engine",
|
| 206 |
+
"kind": "derived_boundary",
|
| 207 |
+
"formula": "midpoint(sunset, next_true_dawn)",
|
| 208 |
+
"fixed_minutes": false
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"id": "last_third_start",
|
| 212 |
+
"label": "بداية الثلث الأخير من الليل",
|
| 213 |
+
"source": "derived_time_engine",
|
| 214 |
+
"kind": "derived_boundary",
|
| 215 |
+
"formula": "sunset + (2/3 * duration(sunset, next_true_dawn))",
|
| 216 |
+
"fixed_minutes": false
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"id": "next_false_dawn",
|
| 220 |
+
"label": "الفجر الكاذب لليوم التالي",
|
| 221 |
+
"source": "astronomy_engine",
|
| 222 |
+
"kind": "observational_estimate",
|
| 223 |
+
"fixed_minutes": false,
|
| 224 |
+
"cycle_link": "false_dawn"
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"id": "next_true_dawn",
|
| 228 |
+
"label": "الفجر الصادق لليوم التالي",
|
| 229 |
+
"source": "prayer_engine",
|
| 230 |
+
"kind": "prayer_boundary",
|
| 231 |
+
"fixed_minutes": false,
|
| 232 |
+
"cycle_link": "true_dawn"
|
| 233 |
+
}
|
| 234 |
+
],
|
| 235 |
+
"aliases": {
|
| 236 |
+
"note": "أسماء بديلة تُحسب في calculation_profile.boundaries وتحيل إلى حد معرّف، وتُستعمل في worship_fiqh_registry ومشغلات التنبيه.",
|
| 237 |
+
"fajr": {
|
| 238 |
+
"alias_of": "true_dawn",
|
| 239 |
+
"label": "الفجر"
|
| 240 |
+
},
|
| 241 |
+
"isha_entry_hanafi": {
|
| 242 |
+
"alias_of": "white_twilight_end",
|
| 243 |
+
"label": "دخول العشاء عند الحنفية (الشفق الأبيض)"
|
| 244 |
+
}
|
| 245 |
+
},
|
| 246 |
+
"derived_windows": [
|
| 247 |
+
{
|
| 248 |
+
"id": "post_sunrise_to_sunrise_clear",
|
| 249 |
+
"start": "sunrise",
|
| 250 |
+
"end": "sunrise_clear",
|
| 251 |
+
"semantic": "فترة زمنية فقط؛ الحكم واللون يحددان في ملفات مستقلة"
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"id": "duha_time_geometry",
|
| 255 |
+
"start": "sunrise_clear",
|
| 256 |
+
"end": "solar_noon",
|
| 257 |
+
"semantic": "نافذة زمنية هندسية فقط؛ لا تحمل حكمًا أو لونًا هنا"
|
| 258 |
+
},
|
| 259 |
+
{
|
| 260 |
+
"id": "solar_noon_to_zawal",
|
| 261 |
+
"start": "solar_noon",
|
| 262 |
+
"end": "zawal",
|
| 263 |
+
"semantic": "انتقال الاستواء إلى الزوال؛ الحكم واللون خارج هذا الملف"
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"id": "sunset_approach_to_sunset",
|
| 267 |
+
"start": "sunset_approach",
|
| 268 |
+
"end": "sunset",
|
| 269 |
+
"semantic": "فترة اقتراب الغروب فقط؛ لا تحمل حكمًا فقهيًا هنا"
|
| 270 |
+
},
|
| 271 |
+
{
|
| 272 |
+
"id": "night",
|
| 273 |
+
"start": "sunset",
|
| 274 |
+
"end": "next_true_dawn",
|
| 275 |
+
"semantic": "الفترة الليلية المستخدمة للاشتقاقات الزمنية"
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"id": "first_third_of_night_window",
|
| 279 |
+
"start": "sunset",
|
| 280 |
+
"end": "first_third_of_night",
|
| 281 |
+
"semantic": "نافذة حسابية فقط؛ الحكم الفقهي خارج هذا الملف."
|
| 282 |
+
},
|
| 283 |
+
{
|
| 284 |
+
"id": "last_third_of_night_window",
|
| 285 |
+
"start": "last_third_start",
|
| 286 |
+
"end": "next_true_dawn",
|
| 287 |
+
"semantic": "نافذة حسابية فقط؛ الحكم والعبادة خارج هذا الملف."
|
| 288 |
+
}
|
| 289 |
+
],
|
| 290 |
+
"ordering": [
|
| 291 |
+
"false_dawn",
|
| 292 |
+
"true_dawn",
|
| 293 |
+
"sunrise",
|
| 294 |
+
"sunrise_clear",
|
| 295 |
+
"solar_noon",
|
| 296 |
+
"zawal",
|
| 297 |
+
"dhuhr",
|
| 298 |
+
"asr_shadow_1",
|
| 299 |
+
"asr_shadow_2",
|
| 300 |
+
"asr",
|
| 301 |
+
"last_daylight_hour_start",
|
| 302 |
+
"sunset_approach",
|
| 303 |
+
"sunset",
|
| 304 |
+
"maghrib",
|
| 305 |
+
"red_twilight_end",
|
| 306 |
+
"white_twilight_end",
|
| 307 |
+
"isha",
|
| 308 |
+
"first_third_of_night",
|
| 309 |
+
"islamic_midnight",
|
| 310 |
+
"last_third_start",
|
| 311 |
+
"next_false_dawn",
|
| 312 |
+
"next_true_dawn"
|
| 313 |
+
],
|
| 314 |
+
"validation": {
|
| 315 |
+
"no_colors": true,
|
| 316 |
+
"no_worship_rulings": true,
|
| 317 |
+
"no_fixed_solar_minute_offsets": true,
|
| 318 |
+
"continuous_cycle": true,
|
| 319 |
+
"implementation_ready": true,
|
| 320 |
+
"supports_madhhab_worship_registry": true,
|
| 321 |
+
"shadow_factor_boundaries_present": true,
|
| 322 |
+
"night_fraction_boundaries_present": true,
|
| 323 |
+
"aliases_resolve": true,
|
| 324 |
+
"solver_constants_in_registry": true
|
| 325 |
+
},
|
| 326 |
+
"integration_contract": {
|
| 327 |
+
"worship_fiqh_registry": "worship_fiqh_registry.json",
|
| 328 |
+
"role_ar": "هذا الملف يحسب الحدود فقط، وملف worship_fiqh_registry.json يختار أي حد تستخدمه العبادة بحسب المذهب.",
|
| 329 |
+
"madhhab_sensitive_outputs": [
|
| 330 |
+
"asr_shadow_1",
|
| 331 |
+
"asr_shadow_2",
|
| 332 |
+
"first_third_of_night",
|
| 333 |
+
"red_twilight_end",
|
| 334 |
+
"white_twilight_end"
|
| 335 |
],
|
| 336 |
+
"hijri_calendar_registry": "hijri_calendar_registry.json",
|
| 337 |
+
"cross_registry_validator": "validate_registries.js"
|
| 338 |
+
},
|
| 339 |
+
"calculation_profile": {
|
| 340 |
+
"id": "inherited_solar_estimates_v1",
|
| 341 |
+
"label_ar": "إعدادات شمسية تقديرية من النسخة القديمة",
|
| 342 |
+
"note_ar": "حساب شمسي تقديري يتغير بالموقع والتاريخ. ارتفاع الشمس 4.5° والشفق 15°/18° إعدادات تقديرية موروثة تحتاج اعتمادًا. الاستواء والزوال حدّا انتقال اتجاه حركة الشمس، دون افتراض فترة بالدقائق؛ هذه ليست مواقيت أذان رسمية.",
|
| 343 |
+
"provenance": {
|
| 344 |
+
"solar_geometry": "index-8.html: sunPosition / solarAltitudeAt",
|
| 345 |
+
"sunrise_clear": "index-8.html: solarFiqhBoundaries, 4.5 degrees",
|
| 346 |
+
"zawal": "fiqh_time_registry_solar_v1_1.json: post_transit_transition / after_upper_solar_transit؛ حل عددي لتغير اتجاه الارتفاع بعد القمة، دون مساواة alias أو عتبة انخفاض مخترعة.",
|
| 347 |
+
"sunset_approach": "index-8.html: estimateSunsetStart, -0.30 degrees",
|
| 348 |
+
"twilight": "spiritual_timeline_v3_fiqh_timers_FINAL.zip: fiqh_time_registry.json, red 15 and white 18 degrees",
|
| 349 |
+
"true_dawn": "index-8.html: FAJR_ANGLE = 18"
|
| 350 |
+
},
|
| 351 |
+
"default_madhhab": "shafii",
|
| 352 |
+
"locations": [
|
| 353 |
+
{
|
| 354 |
+
"id": "amman",
|
| 355 |
+
"name": "عمّان",
|
| 356 |
+
"lat": 31.9454,
|
| 357 |
+
"lng": 35.9284,
|
| 358 |
+
"height": 0,
|
| 359 |
+
"timezone": "Asia/Amman",
|
| 360 |
+
"note": "height يستهلكه solar_engine. timezone للمستهلك: حد اليوم يحتاج منطقة المدينة لا الجهاز عند اختلافهما."
|
| 361 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
],
|
| 363 |
+
"observational_limits": {
|
| 364 |
+
"false_dawn": null,
|
| 365 |
+
"next_false_dawn": null
|
| 366 |
+
},
|
| 367 |
+
"boundaries": {
|
| 368 |
+
"solar_noon": {
|
| 369 |
+
"op": "maximum"
|
| 370 |
+
},
|
| 371 |
+
"true_dawn": {
|
| 372 |
+
"op": "altitude",
|
| 373 |
+
"degrees": -18,
|
| 374 |
+
"direction": "ascending"
|
| 375 |
+
},
|
| 376 |
+
"sunrise": {
|
| 377 |
+
"op": "altitude",
|
| 378 |
+
"degrees": -0.833,
|
| 379 |
+
"direction": "ascending"
|
| 380 |
+
},
|
| 381 |
+
"sunrise_clear": {
|
| 382 |
+
"op": "altitude",
|
| 383 |
+
"degrees": 4.5,
|
| 384 |
+
"direction": "ascending",
|
| 385 |
+
"approximate": true
|
| 386 |
+
},
|
| 387 |
+
"zawal": {
|
| 388 |
+
"op": "post_transit_transition",
|
| 389 |
+
"boundary": "solar_noon",
|
| 390 |
+
"direction": "descending",
|
| 391 |
+
"transition_only": true,
|
| 392 |
+
"note_ar": "الزوال محسوب من بدء انخفاض ارتفاع الشمس بعد الاستواء. يعرض كحد شمسي؛ لا يستنتج الحساب منه فترة نهي ممتدة بالدقائق."
|
| 393 |
+
},
|
| 394 |
+
"sunset_approach": {
|
| 395 |
+
"op": "altitude",
|
| 396 |
+
"degrees": -0.3,
|
| 397 |
+
"direction": "descending",
|
| 398 |
+
"approximate": true
|
| 399 |
+
},
|
| 400 |
+
"sunset": {
|
| 401 |
+
"op": "altitude",
|
| 402 |
+
"degrees": -0.833,
|
| 403 |
+
"direction": "descending"
|
| 404 |
+
},
|
| 405 |
+
"red_twilight_end": {
|
| 406 |
+
"op": "altitude",
|
| 407 |
+
"degrees": -15,
|
| 408 |
+
"direction": "descending",
|
| 409 |
+
"approximate": true
|
| 410 |
+
},
|
| 411 |
+
"white_twilight_end": {
|
| 412 |
+
"op": "altitude",
|
| 413 |
+
"degrees": -18,
|
| 414 |
+
"direction": "descending",
|
| 415 |
+
"approximate": true
|
| 416 |
+
},
|
| 417 |
+
"asr_shadow_1": {
|
| 418 |
+
"op": "shadow",
|
| 419 |
+
"factor": 1
|
| 420 |
+
},
|
| 421 |
+
"asr_shadow_2": {
|
| 422 |
+
"op": "shadow",
|
| 423 |
+
"factor": 2
|
| 424 |
+
},
|
| 425 |
+
"fajr": {
|
| 426 |
+
"op": "alias",
|
| 427 |
+
"boundary": "true_dawn"
|
| 428 |
+
},
|
| 429 |
+
"dhuhr": {
|
| 430 |
+
"op": "alias",
|
| 431 |
+
"boundary": "zawal"
|
| 432 |
+
},
|
| 433 |
+
"maghrib": {
|
| 434 |
+
"op": "alias",
|
| 435 |
+
"boundary": "sunset"
|
| 436 |
+
},
|
| 437 |
+
"asr": {
|
| 438 |
+
"op": "rule_start",
|
| 439 |
+
"rule_id": "asr"
|
| 440 |
+
},
|
| 441 |
+
"isha": {
|
| 442 |
+
"op": "rule_start",
|
| 443 |
+
"rule_id": "isha_entry"
|
| 444 |
+
},
|
| 445 |
+
"isha_entry_hanafi": {
|
| 446 |
+
"op": "alias",
|
| 447 |
+
"boundary": "white_twilight_end"
|
| 448 |
+
},
|
| 449 |
+
"next_true_dawn": {
|
| 450 |
+
"op": "next_day",
|
| 451 |
+
"boundary": "true_dawn"
|
| 452 |
+
},
|
| 453 |
+
"first_third_of_night": {
|
| 454 |
+
"op": "fraction",
|
| 455 |
+
"from": "sunset",
|
| 456 |
+
"to": "next_true_dawn",
|
| 457 |
+
"fraction": 0.3333333333333333
|
| 458 |
+
},
|
| 459 |
+
"islamic_midnight": {
|
| 460 |
+
"op": "fraction",
|
| 461 |
+
"from": "sunset",
|
| 462 |
+
"to": "next_true_dawn",
|
| 463 |
+
"fraction": 0.5
|
| 464 |
+
},
|
| 465 |
+
"last_third_start": {
|
| 466 |
+
"op": "fraction",
|
| 467 |
+
"from": "sunset",
|
| 468 |
+
"to": "next_true_dawn",
|
| 469 |
+
"fraction": 0.6666666666666666
|
| 470 |
+
},
|
| 471 |
+
"last_daylight_hour_start": {
|
| 472 |
+
"op": "fraction",
|
| 473 |
+
"from": "sunrise",
|
| 474 |
+
"to": "sunset",
|
| 475 |
+
"fraction": 0.9166666666666666
|
| 476 |
+
}
|
| 477 |
+
},
|
| 478 |
+
"relation_bindings": {
|
| 479 |
+
"after_isha": "isha",
|
| 480 |
+
"last_third_start_to_next_true_dawn": [
|
| 481 |
"last_third_start",
|
|
|
|
| 482 |
"next_true_dawn"
|
| 483 |
+
]
|
| 484 |
+
},
|
| 485 |
+
"rule_time_bindings": {
|
| 486 |
+
"isha_entry": {
|
| 487 |
+
"end": "next_true_dawn"
|
| 488 |
+
},
|
| 489 |
+
"isha_periods": {
|
| 490 |
+
"start": "isha"
|
| 491 |
+
}
|
| 492 |
+
},
|
| 493 |
+
"notice_runtime": {
|
| 494 |
+
"due_window_seconds": 90,
|
| 495 |
+
"trigger_bindings": {
|
| 496 |
+
"day_start": {
|
| 497 |
+
"boundary": "true_dawn"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
},
|
| 499 |
+
"after_fajr": {
|
| 500 |
+
"boundary": "fajr"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 501 |
},
|
| 502 |
+
"after_dhuhr": {
|
| 503 |
+
"boundary": "dhuhr"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
},
|
| 505 |
+
"after_asr": {
|
| 506 |
+
"boundary": "asr"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
},
|
| 508 |
+
"after_maghrib": {
|
| 509 |
+
"boundary": "maghrib"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 510 |
},
|
| 511 |
+
"after_isha": {
|
| 512 |
+
"boundary": "isha"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 513 |
},
|
| 514 |
+
"before_fajr": {
|
| 515 |
+
"boundary": "fajr",
|
| 516 |
+
"offset_sign": -1
|
|
|
|
|
|
|
|
|
|
|
|
|
| 517 |
},
|
| 518 |
+
"before_jumuah": {
|
| 519 |
+
"boundary": "dhuhr",
|
| 520 |
+
"offset_sign": -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
},
|
| 522 |
+
"duha_start": {
|
| 523 |
+
"boundary": "sunrise_clear"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
},
|
| 525 |
+
"last_third_start": {
|
| 526 |
+
"boundary": "last_third_start"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 527 |
},
|
| 528 |
+
"previous_evening": {
|
| 529 |
+
"boundary": "sunset",
|
| 530 |
+
"day_shift": -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
},
|
| 532 |
+
"sunday_evening": {
|
| 533 |
+
"boundary": "sunset",
|
| 534 |
+
"day_shift": -1
|
|
|
|
| 535 |
},
|
| 536 |
+
"wednesday_evening": {
|
| 537 |
+
"boundary": "sunset",
|
| 538 |
+
"day_shift": -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 539 |
}
|
| 540 |
+
},
|
| 541 |
+
"note_ar": "نافذة استدراك التنبيه سياسة تطبيق فقط. حدود أوقات النهي لا تستخدم هذه الإزاحات. التنبيهات تعمل أثناء فتح الصفحة، ويحدّد سجل الحدث عدد مرات ظهوره."
|
| 542 |
},
|
| 543 |
+
"solar_solver": {
|
| 544 |
+
"time_tolerance_ms": 1000,
|
| 545 |
+
"derivative_sample_ms": 1000,
|
| 546 |
+
"note_ar": "دقة عددية وحدود بحث فقط؛ ليست مدة نهي أو إزاحة زمنية للزوال. scan_step_ms خطوة مسح العبور، وbisect_iterations تكرارات التنصيف، وnoon_bracket_hours نصف نافذة البحث حول الاستواء، وhalf_day_hours نصف اليوم لنوافذ البحث، وdependency_passes أقصى عمق لاعتماد الحدود بعضها على بعض.",
|
| 547 |
+
"scan_step_ms": 300000,
|
| 548 |
+
"bisect_iterations": 36,
|
| 549 |
+
"maximum_iterations": 60,
|
| 550 |
+
"transit_iterations": 80,
|
| 551 |
+
"noon_bracket_hours": 6,
|
| 552 |
+
"half_day_hours": 12,
|
| 553 |
+
"dependency_passes": 5,
|
| 554 |
+
"longitude_degrees_per_hour": 15
|
| 555 |
+
},
|
| 556 |
+
"solar_motion": {
|
| 557 |
+
"engine": "local_solar_geometry",
|
| 558 |
+
"algorithm_reference": "Jean Meeus, Astronomical Algorithms",
|
| 559 |
+
"indicator_position_source": "device_clock_on_continuous_timeline",
|
| 560 |
+
"day_night_source": "computed_sunrise_and_sunset",
|
| 561 |
+
"apparent_horizon_degrees": -0.833,
|
| 562 |
+
"uses_prayer_time_provider": false,
|
| 563 |
+
"note_ar": "حركة المؤشر تتبع وقت الجهاز على الخط المتصل، وحالة الشمس/القمر تتبع ارتفاع الشمس المحسوب للموقع. حد الشروق والغروب الظاهري −0.833°؛ وقد يختلف الرصد الفعلي قليلًا بسبب الغلاف الجوي والأفق المحلي."
|
| 564 |
+
}
|
| 565 |
+
},
|
| 566 |
+
"prayer_calculation": {
|
| 567 |
+
"default_method": "JordanAwqaf",
|
| 568 |
+
"storage_key": "clock_calculation_method_v1",
|
| 569 |
+
"legacy_option": {
|
| 570 |
+
"id": "registry",
|
| 571 |
+
"label": "الحدود الشمسية والسجل الفقهي الحالي"
|
| 572 |
+
},
|
| 573 |
+
"engine": {
|
| 574 |
+
"url": "https://unpkg.com/adhan@4.4.6/lib/bundles/adhan.umd.min.js",
|
| 575 |
+
"version": "4.4.6",
|
| 576 |
+
"timeout_ms": 12000,
|
| 577 |
+
"source": "Adhan JS 4.4.6؛ الحسابات الفلكية مبنية على Astronomical Algorithms لِـ Jean Meeus",
|
| 578 |
+
"local_path": null,
|
| 579 |
+
"offline_note_ar": "يعتمد الرابط الحالي على الإنترنت. ضع نسخة adhan.umd.min.js (الإصدار 4.4.6) بجانب index.html وسمّها هنا في local_path ليعمل الحساب دون اتصال."
|
| 580 |
+
},
|
| 581 |
+
"methods": [
|
| 582 |
+
{
|
| 583 |
+
"id": "JordanAwqaf",
|
| 584 |
+
"label": "الأردن — وزارة الأوقاف",
|
| 585 |
+
"engine_mode": "custom_angles",
|
| 586 |
+
"fajr_angle": 18,
|
| 587 |
+
"isha_angle": 18,
|
| 588 |
+
"adjustments": {
|
| 589 |
+
"maghrib": 5
|
| 590 |
+
},
|
| 591 |
+
"provider_method_id": 23,
|
| 592 |
+
"solar_sunset_is_independent": true,
|
| 593 |
+
"authority_name": "وزارة ��لأوقاف والشؤون والمقدسات الإسلامية — الأردن",
|
| 594 |
+
"method_reference_url": "https://api.aladhan.com/v1/methods",
|
| 595 |
+
"daily_reference_url": "https://www.aliftaa.jo/Default",
|
| 596 |
+
"note_ar": "تطبيق محلي لمعاملات طريقة الأردن المنشورة: الفجر 18°، العشاء 18°، والمغرب بعد الغروب بخمس دقائق. تبقى مواقيت دائرة الإفتاء اليومية مرجع المقارنة الرسمي لمدينة عمّان."
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"id": "MuslimWorldLeague",
|
| 600 |
+
"label": "رابطة العالم الإسلامي"
|
| 601 |
+
},
|
| 602 |
+
{
|
| 603 |
+
"id": "UmmAlQura",
|
| 604 |
+
"label": "أم القرى - مكة"
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"id": "Egyptian",
|
| 608 |
+
"label": "الهيئة المصرية للمساحة"
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"id": "Karachi",
|
| 612 |
+
"label": "كراتشي"
|
| 613 |
+
},
|
| 614 |
+
{
|
| 615 |
+
"id": "Dubai",
|
| 616 |
+
"label": "دبي"
|
| 617 |
+
},
|
| 618 |
+
{
|
| 619 |
+
"id": "Qatar",
|
| 620 |
+
"label": "قطر"
|
| 621 |
+
},
|
| 622 |
+
{
|
| 623 |
+
"id": "Kuwait",
|
| 624 |
+
"label": "الكويت"
|
| 625 |
+
},
|
| 626 |
+
{
|
| 627 |
+
"id": "MoonsightingCommittee",
|
| 628 |
+
"label": "لجنة تحري الهلال"
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"id": "Singapore",
|
| 632 |
+
"label": "سنغافورة / ماليزيا / إندونيسيا"
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"id": "Turkey",
|
| 636 |
+
"label": "تركيا"
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"id": "Tehran",
|
| 640 |
+
"label": "طهران"
|
| 641 |
+
},
|
| 642 |
+
{
|
| 643 |
+
"id": "NorthAmerica",
|
| 644 |
+
"label": "ISNA - أمريكا الشمالية"
|
| 645 |
+
}
|
| 646 |
+
],
|
| 647 |
+
"shadow_factor_to_madhab": {
|
| 648 |
+
"1": "Shafi",
|
| 649 |
+
"2": "Hanafi"
|
| 650 |
+
},
|
| 651 |
+
"madhhab_engine_bindings": {
|
| 652 |
+
"hanafi": {
|
| 653 |
+
"asr_shadow_factor": 2,
|
| 654 |
+
"adhan_madhab": "Hanafi",
|
| 655 |
+
"moonsighting_shafaq": "Abyad"
|
| 656 |
+
},
|
| 657 |
+
"maliki": {
|
| 658 |
+
"asr_shadow_factor": 1,
|
| 659 |
+
"adhan_madhab": "Shafi",
|
| 660 |
+
"moonsighting_shafaq": "Ahmer"
|
| 661 |
+
},
|
| 662 |
+
"shafii": {
|
| 663 |
+
"asr_shadow_factor": 1,
|
| 664 |
+
"adhan_madhab": "Shafi",
|
| 665 |
+
"moonsighting_shafaq": "Ahmer"
|
| 666 |
+
},
|
| 667 |
+
"hanbali": {
|
| 668 |
+
"asr_shadow_factor": 1,
|
| 669 |
+
"adhan_madhab": "Shafi",
|
| 670 |
+
"moonsighting_shafaq": "Ahmer"
|
| 671 |
+
}
|
| 672 |
+
},
|
| 673 |
+
"output_bindings": {
|
| 674 |
+
"fajr": "fajr",
|
| 675 |
+
"dhuhr": "dhuhr",
|
| 676 |
+
"asr": "asr",
|
| 677 |
+
"maghrib": "maghrib",
|
| 678 |
+
"isha": "isha"
|
| 679 |
+
},
|
| 680 |
+
"period_bindings": {
|
| 681 |
+
"fajr": {
|
| 682 |
+
"start": "fajr",
|
| 683 |
+
"end": "sunrise"
|
| 684 |
+
},
|
| 685 |
+
"dhuhr": {
|
| 686 |
+
"start": "dhuhr",
|
| 687 |
+
"end": "asr"
|
| 688 |
+
},
|
| 689 |
+
"asr": {
|
| 690 |
+
"start": "asr",
|
| 691 |
+
"end": "maghrib"
|
| 692 |
+
},
|
| 693 |
+
"maghrib": {
|
| 694 |
+
"start": "maghrib",
|
| 695 |
+
"end": "isha"
|
| 696 |
+
},
|
| 697 |
+
"isha_entry": {
|
| 698 |
+
"start": "isha",
|
| 699 |
+
"end": "next_true_dawn"
|
| 700 |
+
}
|
| 701 |
+
},
|
| 702 |
+
"ramadan_interval": {
|
| 703 |
+
"method": "UmmAlQura",
|
| 704 |
+
"minutes": 120,
|
| 705 |
+
"storage_key": "clock_ummalqura_ramadan_v1"
|
| 706 |
+
},
|
| 707 |
+
"note_ar": "طريقة الأردن هي الافتراضية، وتستخدم معاملات وزارة الأوقاف المنشورة مع إبقاء صفحة دائرة الإفتاء مرجع المقارنة اليومي. فرق خمس دقائق يخص موعد المغرب في هذه الطريقة ولا يغيّر حد الغروب الشمسي المحسوب. تشمل القائمة جميع الطرق المسماة التي يوفرها Adhan JS 4.4.6 إضافة إلى طريقة الأردن المخصصة. مواقيت الصلاة لا تستبدل الحدود الشمسية المستقلة التي تحرك مؤشر الشمس. المذهب الحنفي يأخذ المثلين للعصر، والمذاهب الثلاثة تأخذ المثل؛ وتضبط طريقة لجنة تحري الهلال نوع الشفق كذلك. خيار رمضان لأم القرى يؤكد يدويًا ولا يستنتج من تقويم تقريبي."
|
| 708 |
+
},
|
| 709 |
+
"changelog": [
|
| 710 |
+
"1.6.0: aliases رسمية للحدود المستخدمة في الفقه والمحرك (fajr, isha_entry_hanafi) كانت مفقودة من boundaries",
|
| 711 |
+
"1.6.0: كل ثوابت الحل العددي (خطوة المسح، التكرارات، نافذة البحث) انتقلت من solar_engine.js إلى solar_solver",
|
| 712 |
+
"1.6.0: إضافة height وtimezone لموقع عمّان (height يستهلكه المحرك، وtimezone للمستهلك المستقبلي)",
|
| 713 |
+
"1.6.0: حقل local_path لمحرك Adhan حتى لا يعتمد التطبيق على CDN وحده",
|
| 714 |
+
"1.6.0: المدقق validate_registries.js يفحص الاتساق بين هذا الملف وworship_fiqh_registry",
|
| 715 |
+
"1.6.0: حد last_daylight_hour_start (11/12 من النهار) لعرض ساعة الإجابة يوم الجمعة"
|
| 716 |
+
]
|
| 717 |
}
|
hijri_calendar_engine.js
CHANGED
|
@@ -1,86 +1,76 @@
|
|
| 1 |
'use strict';
|
| 2 |
|
| 3 |
// Pure Hijri-calendar matching. UI preferences and Registry access stay in RegistryApp.
|
| 4 |
-
// Calendar
|
| 5 |
globalThis.HijriCalendarEngine = (() => {
|
| 6 |
-
|
| 7 |
-
const
|
| 8 |
-
|
| 9 |
-
const
|
| 10 |
-
const
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
const
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
}
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
return
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
length
|
| 56 |
-
|
| 57 |
-
return {year:here.year,month:here.month,day:here.day,length,startMs,endMs:civilNoon(startMs,length-1)};
|
| 58 |
-
}
|
| 59 |
-
// First civil day (noon stamp) from fromMs on whose Hijri date is {month,day}. month: number|null (any),
|
| 60 |
-
// day: number|'last'. Returns {ms,hijri} or null (e.g. day 30 in a 29-day month is skipped).
|
| 61 |
-
function nextOccurrence({month=null,day},fromMs,options={}){
|
| 62 |
-
for(let i=0;i<=SEARCH_HORIZON_DAYS;i++){
|
| 63 |
-
const stamp=civilNoon(fromMs,i),h=parts(stamp,options);
|
| 64 |
-
if(!h||(month!=null&&h.month!==Number(month)))continue;
|
| 65 |
-
if(day==='last'){const tomorrow=parts(civilNoon(stamp,1),options);if(tomorrow&&tomorrow.month!==h.month)return {ms:stamp,hijri:h};}
|
| 66 |
-
else if(h.day===Number(day))return {ms:stamp,hijri:h};
|
| 67 |
}
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
function matches(event,ms,{parts:resolveParts,forBlocking=false}={}){
|
| 71 |
-
const calendar=event?.calendar_rule||{};
|
| 72 |
-
if(calendar.type==='daily')return true;
|
| 73 |
-
if(calendar.type==='weekly')return calendar.weekday===WEEKDAYS[new Date(ms).getDay()];
|
| 74 |
-
if(calendar.calendar!=='hijri')return !calendar.type;
|
| 75 |
-
const hijri=typeof resolveParts==='function'?resolveParts(ms):null;if(!hijri)return false;
|
| 76 |
-
if(calendar.requires_month_confirmation&&!forBlocking&&hijri.confirmed!==true)return false;
|
| 77 |
-
if(calendar.month!=='every'&&calendar.month!=null&&Number(calendar.month)!==hijri.month)return false;
|
| 78 |
-
if(Array.isArray(calendar.days)&&!calendar.days.map(Number).includes(hijri.day))return false;
|
| 79 |
-
if(calendar.day!=null&&Number(calendar.day)!==hijri.day)return false;
|
| 80 |
-
if(Array.isArray(calendar.day_range)&&(hijri.day<Number(calendar.day_range[0])||hijri.day>Number(calendar.day_range[1])))return false;
|
| 81 |
-
if(Array.isArray(calendar.night_range)&&(hijri.day<Number(calendar.night_range[0])||hijri.day>Number(calendar.night_range[1])))return false;
|
| 82 |
-
if(Array.isArray(calendar.odd_nights)&&!calendar.odd_nights.map(Number).includes(hijri.day))return false;
|
| 83 |
-
return true;
|
| 84 |
-
}
|
| 85 |
-
return Object.freeze({version:'2.0.0',FACTS,configure,parts,partsAtSunset,monthInfo,nextOccurrence,matches,validConfirmation});
|
| 86 |
})();
|
|
|
|
| 1 |
'use strict';
|
| 2 |
|
| 3 |
// Pure Hijri-calendar matching. UI preferences and Registry access stay in RegistryApp.
|
| 4 |
+
// Calendar id, month lengths and scan limits come from hijri_calendar_registry.json via configure().
|
| 5 |
globalThis.HijriCalendarEngine = (() => {
|
| 6 |
+
// Used only when configure() was never called (older callers); the registry always wins.
|
| 7 |
+
const LEGACY=Object.freeze({calendar_id:'islamic',month_lengths:[29,30],months_per_year:12,max_scan_days:400});
|
| 8 |
+
let config=null;
|
| 9 |
+
const cfg=()=>config||LEGACY;
|
| 10 |
+
const DAY=86400000;
|
| 11 |
+
const api={
|
| 12 |
+
configure(registry){
|
| 13 |
+
const next={calendar_id:registry?.calendar?.calendar_id,month_lengths:registry?.month_lengths,months_per_year:registry?.months_per_year,max_scan_days:registry?.max_scan_days};
|
| 14 |
+
const valid=typeof next.calendar_id==='string'&&Array.isArray(next.month_lengths)&&next.month_lengths.every(Number.isInteger)&&Number.isInteger(next.months_per_year)&&next.months_per_year>0&&Number.isInteger(next.max_scan_days)&&next.max_scan_days>0;
|
| 15 |
+
if(!valid)throw new Error('hijri_calendar_registry is incomplete (calendar_id, month_lengths, months_per_year, max_scan_days).');
|
| 16 |
+
config=Object.freeze(next);return api;
|
| 17 |
+
},
|
| 18 |
+
parts(ms,{calendarId=cfg().calendar_id,offsetDays=0,maxOffsetDays=0,confirmations=[]}={}){
|
| 19 |
+
try{
|
| 20 |
+
const actual=new Date(ms),civilStamp=Date.UTC(actual.getFullYear(),actual.getMonth(),actual.getDate());
|
| 21 |
+
for(const month of confirmations){
|
| 22 |
+
if(!api.validConfirmation(month))continue;
|
| 23 |
+
const elapsed=Math.round((civilStamp-Date.parse(month.start+'T00:00:00Z'))/DAY);
|
| 24 |
+
if(elapsed>=0&&elapsed<month.length)return {year:month.year,month:month.month,day:elapsed+1,confirmed:true};
|
| 25 |
+
}
|
| 26 |
+
const date=new Date(ms),offset=Number(offsetDays),limit=Number(maxOffsetDays);
|
| 27 |
+
if(Number.isInteger(offset)&&Number.isFinite(limit)&&Math.abs(offset)<=limit)date.setDate(date.getDate()+offset);
|
| 28 |
+
const formatted=new Intl.DateTimeFormat('en-US',{calendar:calendarId,year:'numeric',month:'numeric',day:'numeric'}).formatToParts(date);
|
| 29 |
+
const value=type=>Number(formatted.find(part=>part.type===type)?.value);
|
| 30 |
+
const result={year:value('year'),month:value('month'),day:value('day')};
|
| 31 |
+
return Object.values(result).every(Number.isFinite)?result:null;
|
| 32 |
+
}catch{return null;}
|
| 33 |
+
},
|
| 34 |
+
// The Hijri day begins at sunset: from sunsetMs onward the date is the next civil day's Hijri date.
|
| 35 |
+
// sunsetMs comes from the solar engine; this module stays free of solar geometry.
|
| 36 |
+
partsAtSunset(ms,sunsetMs,options={}){
|
| 37 |
+
if(!Number.isFinite(sunsetMs)||ms<sunsetMs)return api.parts(ms,options);
|
| 38 |
+
const next=new Date(ms);next.setDate(next.getDate()+1);
|
| 39 |
+
return api.parts(next.getTime(),options);
|
| 40 |
+
},
|
| 41 |
+
matches(event,ms,{parts,forBlocking=false}={}){
|
| 42 |
+
const calendar=event?.calendar_rule||{};
|
| 43 |
+
if(calendar.type==='daily')return true;
|
| 44 |
+
if(calendar.type==='weekly'){
|
| 45 |
+
const weekday=new Intl.DateTimeFormat('en-US',{weekday:'long'}).format(new Date(ms)).toLowerCase();
|
| 46 |
+
return calendar.weekday===weekday;
|
| 47 |
}
|
| 48 |
+
if(calendar.calendar!=='hijri')return !calendar.type;
|
| 49 |
+
const hijri=typeof parts==='function'?parts(ms):null;if(!hijri)return false;
|
| 50 |
+
if(calendar.requires_month_confirmation&&!forBlocking&&hijri.confirmed!==true)return false;
|
| 51 |
+
if(calendar.month!=='every'&&calendar.month!=null&&Number(calendar.month)!==hijri.month)return false;
|
| 52 |
+
if(Array.isArray(calendar.days)&&!calendar.days.map(Number).includes(hijri.day))return false;
|
| 53 |
+
if(calendar.day!=null&&Number(calendar.day)!==hijri.day)return false;
|
| 54 |
+
if(Array.isArray(calendar.day_range)&&(hijri.day<Number(calendar.day_range[0])||hijri.day>Number(calendar.day_range[1])))return false;
|
| 55 |
+
if(Array.isArray(calendar.night_range)&&(hijri.day<Number(calendar.night_range[0])||hijri.day>Number(calendar.night_range[1])))return false;
|
| 56 |
+
if(Array.isArray(calendar.odd_nights)&&!calendar.odd_nights.map(Number).includes(hijri.day))return false;
|
| 57 |
+
return true;
|
| 58 |
+
},
|
| 59 |
+
// For rules that carry a bare calendar_rule (worship_fiqh_registry): same semantics as matches().
|
| 60 |
+
ruleActive(calendarRule,ms,context={}){return api.matches({calendar_rule:calendarRule},ms,context);},
|
| 61 |
+
// First civil day (local noon) at or after fromMs on which the event matches, scanning at most max_scan_days.
|
| 62 |
+
nextOccurrence(event,fromMs,{parts,forBlocking=false}={}){
|
| 63 |
+
const start=new Date(fromMs);start.setHours(12,0,0,0);
|
| 64 |
+
for(let i=0;i<cfg().max_scan_days;i++){
|
| 65 |
+
const day=new Date(start);day.setDate(start.getDate()+i);
|
| 66 |
+
if(api.matches(event,day.getTime(),{parts,forBlocking}))return day.getTime();
|
| 67 |
+
}
|
| 68 |
+
return null;
|
| 69 |
+
},
|
| 70 |
+
validConfirmation(value){
|
| 71 |
+
if(!value||!Number.isInteger(value.year)||value.year<1||!Number.isInteger(value.month)||value.month<1||value.month>cfg().months_per_year||!cfg().month_lengths.includes(value.length)||!/^\d{4}-\d{2}-\d{2}$/.test(value.start||''))return false;
|
| 72 |
+
const date=new Date(value.start+'T00:00:00Z');return Number.isFinite(date.getTime())&&date.toISOString().slice(0,10)===value.start;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
}
|
| 74 |
+
};
|
| 75 |
+
return Object.freeze(api);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
})();
|
hijri_calendar_registry.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_name": "islamic_clock_hijri_calendar_registry",
|
| 3 |
+
"schema_version": "1.0.0",
|
| 4 |
+
"registry_id": "hijri_calendar",
|
| 5 |
+
"purpose": "إعدادات محرك التقويم الهجري. لا يحتوي أحكامًا ولا مناسبات.",
|
| 6 |
+
"calendar": {
|
| 7 |
+
"calendar_id": "islamic",
|
| 8 |
+
"alternatives": [
|
| 9 |
+
{ "id": "islamic-umalqura", "label": "أم القرى" },
|
| 10 |
+
{ "id": "islamic-civil", "label": "الجدولي المدني" },
|
| 11 |
+
{ "id": "islamic-tbla", "label": "الجدولي الفلكي" },
|
| 12 |
+
{ "id": "islamic-rgsa", "label": "الرؤية السعودية (تقريبي)" }
|
| 13 |
+
],
|
| 14 |
+
"note_ar": "التقويم المحسوب تقدير. ثبوت بداية الشهر يكون بالرؤية أو إعلان الجهة المعتمدة، وتُدخَل نتيجته عبر confirmations في المحرك فتتقدم على الحساب."
|
| 15 |
+
},
|
| 16 |
+
"day_starts_at": "maghrib",
|
| 17 |
+
"month_lengths": [29, 30],
|
| 18 |
+
"months_per_year": 12,
|
| 19 |
+
"max_scan_days": 400,
|
| 20 |
+
"validation": { "no_rulings": true, "no_events": true }
|
| 21 |
+
}
|
solar_engine.js
CHANGED
|
@@ -1,26 +1,19 @@
|
|
| 1 |
-
// Astronomy Engine API adapter. UTC is used internally.
|
| 2 |
-
//
|
| 3 |
-
// (calculation_profile.solar_solver). Only unit conversions live in this file.
|
| 4 |
globalThis.SolarEngine = (() => {
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
| 9 |
const ready=()=>Boolean(globalThis.Astronomy?.Equator&&globalThis.Astronomy?.Horizon);
|
| 10 |
-
function readSolver(solver){
|
| 11 |
-
if(!solver)return null;
|
| 12 |
-
return REQUIRED_SOLVER.every(key=>Number(solver[key])>0)?solver:null;
|
| 13 |
-
}
|
| 14 |
-
// Call once with profile.solar_solver; day() also does this automatically.
|
| 15 |
-
function configure(solver){solverCfg=readSolver(solver);return Boolean(solverCfg);}
|
| 16 |
-
const noonGuess=(day,loc)=>day+D/2-loc.lng/TURN*D;
|
| 17 |
-
const observerFor=loc=>new globalThis.Astronomy.Observer(loc.lat,loc.lng,loc.height||0);
|
| 18 |
-
|
| 19 |
function position(ms,loc){
|
| 20 |
if(!ready())return null;
|
| 21 |
-
const A=globalThis.Astronomy,date=new Date(ms),observer=
|
| 22 |
const equator=A.Equator(A.Body.Sun,date,observer,true,true);
|
| 23 |
-
// No extra refraction here: the registry's
|
| 24 |
// incorporates the standard apparent limb/refraction allowance.
|
| 25 |
const horizon=A.Horizon(date,observer,equator.ra,equator.dec,null);
|
| 26 |
return {decl:equator.dec,ra:equator.ra,altitude:horizon.altitude,azimuth:horizon.azimuth};
|
|
@@ -28,87 +21,68 @@ globalThis.SolarEngine = (() => {
|
|
| 28 |
function altitude(ms,loc){
|
| 29 |
return position(ms,loc)?.altitude??null;
|
| 30 |
}
|
| 31 |
-
function maximum(day,loc
|
| 32 |
-
|
| 33 |
-
const guess=
|
| 34 |
-
for(let i=0;i<
|
| 35 |
return (lo+hi)/2;
|
| 36 |
}
|
| 37 |
// Resolve the sign change of the solar altitude rate. The bracket width is
|
| 38 |
// numerical uncertainty, never a religious duration or an offset after noon.
|
| 39 |
-
function transitTransition(day,loc,
|
| 40 |
-
|
| 41 |
-
const tolerance=
|
| 42 |
-
|
|
|
|
|
|
|
| 43 |
const rate=t=>altitude(t+sample/2,loc)-altitude(t-sample/2,loc);
|
| 44 |
-
let lo=guess-
|
| 45 |
if(!(rate(lo)>0&&rate(hi)<0))return null;
|
| 46 |
-
for(let i=0;i<
|
| 47 |
const mid=(lo+hi)/2;if(rate(mid)<0)hi=mid;else lo=mid;
|
| 48 |
}
|
| 49 |
if(!(rate(hi)<0))return null;
|
| 50 |
return {at:(lo+hi)/2,after:hi,before:lo,uncertainty_ms:hi-lo};
|
| 51 |
}
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
try{
|
| 57 |
-
const hit=A.SearchAltitude(A.Body.Sun,observerFor(loc),direction==='ascending'?1:-1,new Date(lo),(hi-lo)/D,target);
|
| 58 |
-
const at=hit?hit.date.getTime():null;
|
| 59 |
-
return {ok:true,at:at!=null&&at>=lo&&at<=hi?at:null};
|
| 60 |
-
}catch{return {ok:false,at:null};}
|
| 61 |
-
}
|
| 62 |
-
function crossing(lo,hi,target,direction,loc,cfg=solverCfg){
|
| 63 |
-
if(!cfg)return null;
|
| 64 |
-
if(cfg.use_astronomy_search_functions&&typeof globalThis.Astronomy?.SearchAltitude==='function'){
|
| 65 |
-
const fast=searchAltitude(lo,hi,target,direction,loc);
|
| 66 |
-
if(fast.ok)return fast.at;
|
| 67 |
-
}
|
| 68 |
-
const step=cfg.scan_step_ms,rising=direction==='ascending';let prev=lo,pv=altitude(lo,loc)-target;
|
| 69 |
for(let t=lo+step;t<=hi+1;t=Math.min(t+step,hi)){
|
| 70 |
const val=altitude(t,loc)-target;
|
| 71 |
if(rising?pv<=0&&val>=0:pv>=0&&val<=0){
|
| 72 |
-
let a=prev,b=t;for(let j=0;j<
|
| 73 |
}
|
| 74 |
if(t===hi)break;prev=t;pv=val;
|
| 75 |
}
|
| 76 |
return null;
|
| 77 |
}
|
| 78 |
-
// normal | always_up | always_down, from the registry's sunrise altitude. Lets the UI
|
| 79 |
-
// explain why twilight/sunrise boundaries are unavailable instead of showing nothing.
|
| 80 |
-
function polarState(noon,loc,profile){
|
| 81 |
-
const horizon=profile?.boundaries?.sunrise?.degrees;
|
| 82 |
-
if(!Number.isFinite(horizon)||!Number.isFinite(noon))return null;
|
| 83 |
-
const top=altitude(noon,loc),bottom=altitude(noon+D/2,loc);
|
| 84 |
-
if(top==null||bottom==null)return null;
|
| 85 |
-
return bottom>horizon?'always_up':top<horizon?'always_down':'normal';
|
| 86 |
-
}
|
| 87 |
function day(day,loc,profile,worship,madhhab){
|
| 88 |
-
if(!ready())return {day,boundaries:{},engineUnavailable:true
|
| 89 |
-
|
| 90 |
-
if(!
|
| 91 |
-
|
| 92 |
-
const transition=transitTransition(day,loc,
|
| 93 |
-
const noon=transition?.at??maximum(day,loc
|
|
|
|
| 94 |
const basic=(id,def)=>{
|
| 95 |
if(def.op==='maximum')return noon;
|
| 96 |
if(def.op==='post_transit_transition')return transition?.after??null;
|
| 97 |
-
if(def.op==='altitude')return crossing(def.direction==='ascending'?noon-
|
| 98 |
-
if(def.op==='altitude_drop')return crossing(noon,noon+
|
| 99 |
if(def.op==='shadow'){
|
| 100 |
const peak=altitude(noon,loc);if(peak<=0)return null;
|
| 101 |
const target=Math.atan(1/(def.factor+1/Math.tan(peak*rad)))/rad;
|
| 102 |
-
return crossing(noon,noon+
|
| 103 |
}
|
| 104 |
return null;
|
| 105 |
};
|
| 106 |
Object.entries(defs).forEach(([id,def])=>{out[id]=basic(id,def)});
|
| 107 |
-
const nextNoon=maximum(day+D,loc
|
| 108 |
-
for(let pass=0;pass<
|
| 109 |
if(def.op==='alias')out[id]=out[def.boundary]??null;
|
| 110 |
if(def.op==='next_day'){
|
| 111 |
-
const target=defs[def.boundary];out[id]=target?.op==='altitude'?crossing(nextNoon-
|
| 112 |
}
|
| 113 |
if(def.op==='rule_start'){
|
| 114 |
const rule=worship.rules.find(r=>r.id===def.rule_id),choice=rule?.madhhab?.[madhhab];
|
|
@@ -116,34 +90,34 @@ globalThis.SolarEngine = (() => {
|
|
| 116 |
}
|
| 117 |
if(def.op==='fraction')out[id]=out[def.from]!=null&&out[def.to]!=null?out[def.from]+def.fraction*(out[def.to]-out[def.from]):null;
|
| 118 |
});
|
| 119 |
-
|
| 120 |
-
Object.
|
| 121 |
-
return {day,boundaries:out,solar_transition:transition,
|
| 122 |
}
|
| 123 |
-
// options.
|
| 124 |
-
//
|
| 125 |
-
//
|
| 126 |
function periods(days,profile,worship,madhhab,styles,scheduleBindings=null,options={}){
|
| 127 |
-
const
|
| 128 |
-
const
|
| 129 |
-
|
| 130 |
-
const
|
| 131 |
-
|
| 132 |
-
if(estimate?.deprecated_alias_of){key=estimate.deprecated_alias_of;estimate=table[key];}
|
| 133 |
-
if(!estimate)return null;
|
| 134 |
-
const override=options.display_estimate_overrides?.[key];
|
| 135 |
-
if(override&&(!estimate.user_choices_before_minutes||estimate.user_choices_before_minutes.includes(Number(override.before_minutes))))return {...estimate,...override,id:key};
|
| 136 |
-
return {...estimate,id:key};
|
| 137 |
};
|
|
|
|
| 138 |
for(const d of days){const b=d.boundaries;
|
| 139 |
for(const rule of worship.rules){
|
| 140 |
const state=styles.category_states[rule.category];if(!state)continue;
|
| 141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
const choice=rule.madhhab?.[madhhab];const common={...rule.common,...(typeof choice==='object'?choice:{}),...profile.rule_time_bindings?.[rule.id]};
|
| 143 |
if(scheduleBindings&&d.methodUnavailable&&state!==styles.category_states.solar_prayer_restriction)continue;
|
| 144 |
const scheduled=scheduleBindings?.[rule.id];const windows=scheduled?[scheduled]:(typeof choice==='object'&&choice.windows)||rule.windows||[common];
|
| 145 |
for(const w of windows){
|
| 146 |
-
const weekday=[
|
| 147 |
if((w.exclude_weekdays||common.exclude_weekdays||[]).includes(weekday))continue;
|
| 148 |
const requires=w.requires||common.requires||rule.trigger?.requires;
|
| 149 |
const activation=w.activation||common.activation||(requires?'after_prayer':'boundary');
|
|
@@ -151,10 +125,10 @@ globalThis.SolarEngine = (() => {
|
|
| 151 |
// Preserve the chosen school's outer limit, not a fabricated universal end.
|
| 152 |
const endId=w.end||common.end||w.outer_end||common.outer_end||w.necessity_end||common.necessity_end||rule.trigger?.end;
|
| 153 |
let start=b[startId],end=b[endId];
|
| 154 |
-
const
|
| 155 |
-
if(estimate){const center=b[estimate.boundary];if(center!=null){start=center-
|
| 156 |
-
const
|
| 157 |
-
if(endEstimate){const center=b[endEstimate.boundary];if(center!=null)end=center-
|
| 158 |
if(start!=null&&end!=null&&end>=start){
|
| 159 |
const row={id:rule.id,start,end,point:!estimate&&!endEstimate&&(end===start||Boolean(profile.boundaries[endId]?.transition_only)),startId,endId,state,rule,day:d.day,calculationMethod:scheduled?d.calculationMethod:null,conditional:rule.category==='prayer_restriction'||activation==='after_prayer'||Boolean(requires),requires,activation,displayEstimate:estimate||null,displayEndEstimate:endEstimate||null};out.push(row);
|
| 160 |
for(const binding of styles.preference_bindings||[]){
|
|
@@ -170,5 +144,6 @@ globalThis.SolarEngine = (() => {
|
|
| 170 |
}
|
| 171 |
return out;
|
| 172 |
}
|
| 173 |
-
|
|
|
|
| 174 |
})();
|
|
|
|
| 1 |
+
// Astronomy Engine 2.1.19 API adapter. UTC is used internally.
|
| 2 |
+
// All display/ruling thresholds are read from fiqh_time_registry.json.
|
|
|
|
| 3 |
globalThis.SolarEngine = (() => {
|
| 4 |
+
// Unit conversions only. Every tolerance, step and iteration count comes from
|
| 5 |
+
// profile.solar_solver in fiqh_time_registry.json (see configure()).
|
| 6 |
+
const H=3600000, D=24*H, rad=Math.PI/180, MIN=60000;
|
| 7 |
+
const WEEKDAYS=['sunday','monday','tuesday','wednesday','thursday','friday','saturday'];
|
| 8 |
+
let solver=null,api=null;
|
| 9 |
+
const need=key=>{const v=Number(solver?.[key]);if(!(v>0))throw new Error('solar_solver.'+key+' is missing in fiqh_time_registry.json (SolarEngine.configure(profile.solar_solver))');return v;};
|
| 10 |
+
const configure=config=>{solver=config||null;return api;};
|
| 11 |
const ready=()=>Boolean(globalThis.Astronomy?.Equator&&globalThis.Astronomy?.Horizon);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
function position(ms,loc){
|
| 13 |
if(!ready())return null;
|
| 14 |
+
const A=globalThis.Astronomy,date=new Date(ms),observer=new A.Observer(loc.lat,loc.lng,loc.height||0);
|
| 15 |
const equator=A.Equator(A.Body.Sun,date,observer,true,true);
|
| 16 |
+
// No extra refraction here: the registry's -0.833 degree horizon already
|
| 17 |
// incorporates the standard apparent limb/refraction allowance.
|
| 18 |
const horizon=A.Horizon(date,observer,equator.ra,equator.dec,null);
|
| 19 |
return {decl:equator.dec,ra:equator.ra,altitude:horizon.altitude,azimuth:horizon.azimuth};
|
|
|
|
| 21 |
function altitude(ms,loc){
|
| 22 |
return position(ms,loc)?.altitude??null;
|
| 23 |
}
|
| 24 |
+
function maximum(day,loc){
|
| 25 |
+
const half=need('half_day_hours')*H,bracket=need('noon_bracket_hours')*H;
|
| 26 |
+
const guess=day+half-loc.lng/need('longitude_degrees_per_hour')*H;let lo=guess-bracket,hi=guess+bracket;
|
| 27 |
+
for(let i=0;i<need('maximum_iterations');i++){const a=lo+(hi-lo)/3,b=hi-(hi-lo)/3;if(altitude(a,loc)<altitude(b,loc))lo=a;else hi=b;}
|
| 28 |
return (lo+hi)/2;
|
| 29 |
}
|
| 30 |
// Resolve the sign change of the solar altitude rate. The bracket width is
|
| 31 |
// numerical uncertainty, never a religious duration or an offset after noon.
|
| 32 |
+
function transitTransition(day,loc,config){
|
| 33 |
+
if(config)configure(config);
|
| 34 |
+
const tolerance=Number(solver?.time_tolerance_ms),sample=Number(solver?.derivative_sample_ms);
|
| 35 |
+
if(!(tolerance>0&&sample>0))return null;
|
| 36 |
+
const half=need('half_day_hours')*H,bracket=need('noon_bracket_hours')*H;
|
| 37 |
+
const guess=day+half-loc.lng/need('longitude_degrees_per_hour')*H;
|
| 38 |
const rate=t=>altitude(t+sample/2,loc)-altitude(t-sample/2,loc);
|
| 39 |
+
let lo=guess-bracket,hi=guess+bracket;
|
| 40 |
if(!(rate(lo)>0&&rate(hi)<0))return null;
|
| 41 |
+
for(let i=0;i<need('transit_iterations')&&hi-lo>tolerance;i++){
|
| 42 |
const mid=(lo+hi)/2;if(rate(mid)<0)hi=mid;else lo=mid;
|
| 43 |
}
|
| 44 |
if(!(rate(hi)<0))return null;
|
| 45 |
return {at:(lo+hi)/2,after:hi,before:lo,uncertainty_ms:hi-lo};
|
| 46 |
}
|
| 47 |
+
function crossing(lo,hi,target,direction,loc){
|
| 48 |
+
const step=need('scan_step_ms'),iterations=need('bisect_iterations');
|
| 49 |
+
const rising=direction==='ascending';let prev=lo,pv=altitude(lo,loc)-target;
|
| 50 |
+
// hi+1: one millisecond of numerical slack so the final bracket end is tested.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
for(let t=lo+step;t<=hi+1;t=Math.min(t+step,hi)){
|
| 52 |
const val=altitude(t,loc)-target;
|
| 53 |
if(rising?pv<=0&&val>=0:pv>=0&&val<=0){
|
| 54 |
+
let a=prev,b=t;for(let j=0;j<iterations;j++){const m=(a+b)/2,v=altitude(m,loc)-target;if(rising?v<0:v>0)a=m;else b=m;}return(a+b)/2;
|
| 55 |
}
|
| 56 |
if(t===hi)break;prev=t;pv=val;
|
| 57 |
}
|
| 58 |
return null;
|
| 59 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
function day(day,loc,profile,worship,madhhab){
|
| 61 |
+
if(!ready())return {day,boundaries:{},engineUnavailable:true};
|
| 62 |
+
configure(profile.solar_solver);
|
| 63 |
+
if(!worship?.madhhabs?.[madhhab])throw new Error('Unknown madhhab: '+madhhab);
|
| 64 |
+
const half=need('half_day_hours')*H;
|
| 65 |
+
const transition=transitTransition(day,loc,profile.solar_solver);
|
| 66 |
+
const noon=transition?.at??maximum(day,loc), out={}, defs=profile.boundaries, warnings=[];
|
| 67 |
+
if(!transition)warnings.push('transit_unresolved');
|
| 68 |
const basic=(id,def)=>{
|
| 69 |
if(def.op==='maximum')return noon;
|
| 70 |
if(def.op==='post_transit_transition')return transition?.after??null;
|
| 71 |
+
if(def.op==='altitude')return crossing(def.direction==='ascending'?noon-half:noon,def.direction==='ascending'?noon:noon+half,def.degrees,def.direction,loc);
|
| 72 |
+
if(def.op==='altitude_drop')return crossing(noon,noon+half,altitude(noon,loc)-def.degrees,'descending',loc);
|
| 73 |
if(def.op==='shadow'){
|
| 74 |
const peak=altitude(noon,loc);if(peak<=0)return null;
|
| 75 |
const target=Math.atan(1/(def.factor+1/Math.tan(peak*rad)))/rad;
|
| 76 |
+
return crossing(noon,noon+half,target,'descending',loc);
|
| 77 |
}
|
| 78 |
return null;
|
| 79 |
};
|
| 80 |
Object.entries(defs).forEach(([id,def])=>{out[id]=basic(id,def)});
|
| 81 |
+
const nextNoon=maximum(day+D,loc);
|
| 82 |
+
for(let pass=0;pass<need('dependency_passes');pass++)Object.entries(defs).forEach(([id,def])=>{
|
| 83 |
if(def.op==='alias')out[id]=out[def.boundary]??null;
|
| 84 |
if(def.op==='next_day'){
|
| 85 |
+
const target=defs[def.boundary];out[id]=target?.op==='altitude'?crossing(nextNoon-half,nextNoon,target.degrees,target.direction,loc):null;
|
| 86 |
}
|
| 87 |
if(def.op==='rule_start'){
|
| 88 |
const rule=worship.rules.find(r=>r.id===def.rule_id),choice=rule?.madhhab?.[madhhab];
|
|
|
|
| 90 |
}
|
| 91 |
if(def.op==='fraction')out[id]=out[def.from]!=null&&out[def.to]!=null?out[def.from]+def.fraction*(out[def.to]-out[def.from]):null;
|
| 92 |
});
|
| 93 |
+
// Boundaries that could not be solved (for example twilight at high latitude) are reported, never invented.
|
| 94 |
+
const unresolved=Object.keys(defs).filter(id=>out[id]==null);
|
| 95 |
+
return {day,boundaries:out,solar_transition:transition,unresolved,warnings};
|
| 96 |
}
|
| 97 |
+
// options.ruleActive(rule, dayStamp): decides rules with a Hijri calendar_rule (the engine itself
|
| 98 |
+
// resolves weekly/daily rules). options.displayOverrides: {estimateId:{before_minutes}} accepted only
|
| 99 |
+
// when the value is listed in that estimate's allowed_before_minutes.
|
| 100 |
function periods(days,profile,worship,madhhab,styles,scheduleBindings=null,options={}){
|
| 101 |
+
const {ruleActive=null,displayOverrides=null}=options||{};
|
| 102 |
+
const lookup=(id,rule)=>id?(worship.display_estimates?.[id]||rule.window_display_estimates?.[id]||null):null;
|
| 103 |
+
const beforeMinutes=(id,estimate)=>{
|
| 104 |
+
const want=displayOverrides?.[id]?.before_minutes,allowed=estimate.allowed_before_minutes;
|
| 105 |
+
return Number.isFinite(want)&&Array.isArray(allowed)&&allowed.includes(want)?want:Number(estimate.before_minutes||0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
};
|
| 107 |
+
const out=[];
|
| 108 |
for(const d of days){const b=d.boundaries;
|
| 109 |
for(const rule of worship.rules){
|
| 110 |
const state=styles.category_states[rule.category];if(!state)continue;
|
| 111 |
+
const calendar=rule.calendar_rule;
|
| 112 |
+
if(calendar){
|
| 113 |
+
if(calendar.type==='weekly'){if(calendar.weekday!==WEEKDAYS[new Date(d.day).getUTCDay()])continue;}
|
| 114 |
+
else if(calendar.type!=='daily'&&!(typeof ruleActive==='function'&&ruleActive(rule,d.day)))continue;
|
| 115 |
+
}
|
| 116 |
const choice=rule.madhhab?.[madhhab];const common={...rule.common,...(typeof choice==='object'?choice:{}),...profile.rule_time_bindings?.[rule.id]};
|
| 117 |
if(scheduleBindings&&d.methodUnavailable&&state!==styles.category_states.solar_prayer_restriction)continue;
|
| 118 |
const scheduled=scheduleBindings?.[rule.id];const windows=scheduled?[scheduled]:(typeof choice==='object'&&choice.windows)||rule.windows||[common];
|
| 119 |
for(const w of windows){
|
| 120 |
+
const weekday=WEEKDAYS[new Date(d.day).getUTCDay()];
|
| 121 |
if((w.exclude_weekdays||common.exclude_weekdays||[]).includes(weekday))continue;
|
| 122 |
const requires=w.requires||common.requires||rule.trigger?.requires;
|
| 123 |
const activation=w.activation||common.activation||(requires?'after_prayer':'boundary');
|
|
|
|
| 125 |
// Preserve the chosen school's outer limit, not a fabricated universal end.
|
| 126 |
const endId=w.end||common.end||w.outer_end||common.outer_end||w.necessity_end||common.necessity_end||rule.trigger?.end;
|
| 127 |
let start=b[startId],end=b[endId];
|
| 128 |
+
const estimateId=w.display_estimate_id,estimate=lookup(estimateId,rule);
|
| 129 |
+
if(estimate){const center=b[estimate.boundary];if(center!=null){start=center-beforeMinutes(estimateId,estimate)*MIN;end=center+Number(estimate.after_minutes||0)*MIN;}}
|
| 130 |
+
const endEstimateId=w.display_end_estimate_id||common.display_end_estimate_id,endEstimate=lookup(endEstimateId,rule);
|
| 131 |
+
if(endEstimate){const center=b[endEstimate.boundary];if(center!=null)end=center-beforeMinutes(endEstimateId,endEstimate)*MIN;}
|
| 132 |
if(start!=null&&end!=null&&end>=start){
|
| 133 |
const row={id:rule.id,start,end,point:!estimate&&!endEstimate&&(end===start||Boolean(profile.boundaries[endId]?.transition_only)),startId,endId,state,rule,day:d.day,calculationMethod:scheduled?d.calculationMethod:null,conditional:rule.category==='prayer_restriction'||activation==='after_prayer'||Boolean(requires),requires,activation,displayEstimate:estimate||null,displayEndEstimate:endEstimate||null};out.push(row);
|
| 134 |
for(const binding of styles.preference_bindings||[]){
|
|
|
|
| 144 |
}
|
| 145 |
return out;
|
| 146 |
}
|
| 147 |
+
api=Object.freeze({ready,configure,position,altitude,maximum,transitTransition,crossing,day,periods});
|
| 148 |
+
return api;
|
| 149 |
})();
|
validate_registries.js
CHANGED
|
@@ -1,87 +1,71 @@
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
const
|
| 6 |
-
const
|
| 7 |
-
const
|
| 8 |
const errors = [], warnings = [];
|
| 9 |
const err = (m) => errors.push(m), warn = (m) => warnings.push(m);
|
| 10 |
|
|
|
|
|
|
|
| 11 |
const profile = time.calculation_profile;
|
| 12 |
-
const
|
| 13 |
-
const
|
| 14 |
-
const known =
|
| 15 |
-
const relationIds = new Set(Object.keys(profile.relation_bindings || {}));
|
| 16 |
-
const dup = (list, label) => { const s = new Set(); list.forEach((x) => { if (s.has(x)) err(`${label}: معرّف مكرر ${x}`); s.add(x); }); };
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
if (def.op === "alias" && !known.has(def.boundary)) err(`op alias ${id}: الهدف ${def.boundary} غير معرّف`);
|
| 28 |
-
if (def.op === "next_day" && !opIds.has(def.boundary)) err(`op next_day ${id}: الهدف ${def.boundary} بلا op`);
|
| 29 |
-
if (def.op === "fraction") [def.from, def.to].forEach((x) => { if (!opIds.has(x)) err(`op fraction ${id}: ${x} بلا op`); });
|
| 30 |
-
if (def.op === "rule_start" && !worship.rules.some((r) => r.id === def.rule_id)) err(`op rule_start ${id}: القاعدة ${def.rule_id} غير موجودة`);
|
| 31 |
-
if (def.op === "shadow" && !Number.isFinite(def.factor)) err(`op shadow ${id}: factor مفقود`);
|
| 32 |
-
if (def.op === "altitude" && !(Number.isFinite(def.degrees) && ["ascending", "descending"].includes(def.direction))) err(`op altitude ${id}: degrees/direction غير صالحة`);
|
| 33 |
-
});
|
| 34 |
-
Object.entries(profile.relation_bindings || {}).forEach(([k, v]) => [].concat(v).forEach((id) => { if (!known.has(id)) err(`relation_bindings.${k}: ${id} غير معرّف`); }));
|
| 35 |
-
Object.entries(profile.notice_runtime.trigger_bindings).forEach(([k, v]) => { if (!known.has(v.boundary)) err(`trigger_bindings.${k}: ${v.boundary} غير معرّف`); });
|
| 36 |
-
Object.entries(profile.rule_time_bindings || {}).forEach(([k]) => { if (!worship.rules.some((r) => r.id === k)) warn(`rule_time_bindings.${k}: لا توجد قاعدة بهذا المعرّف`); });
|
| 37 |
-
if (!opIds.has(time.daily_cycle.anchor)) {
|
| 38 |
-
const fb = time.daily_cycle.anchor_fallback;
|
| 39 |
-
if (fb && opIds.has(fb)) { /* مغطّى بالاحتياط */ }
|
| 40 |
-
else warn(`daily_cycle.anchor = ${time.daily_cycle.anchor} لا يملك op ولا anchor_fallback صالحًا، فقيمته null دائمًا`);
|
| 41 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
/*
|
| 44 |
-
const
|
| 45 |
-
const
|
| 46 |
-
const
|
| 47 |
-
const
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
(
|
| 52 |
-
};
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
Object.keys(worship.madhhabs)
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
const
|
| 77 |
-
if (worship.validation.no_fixed_solar_minute_offsets === true && fixedMinutes && !(worship.validation.display_only_estimates || []).length) warn("validation.no_fixed_solar_minute_offsets=true لكن توجد دقائق ثابتة في display_estimates ولم تُعلَن display_only_estimates");
|
| 78 |
-
|
| 79 |
-
/* sky */
|
| 80 |
-
["sky_color_model", "objects"].forEach((k) => { if (!sky[k]) err(`sky: المفتاح ${k} مفقود`); });
|
| 81 |
-
const stops = (sky.sky_color_model || {}).gradient_stops || [];
|
| 82 |
-
stops.forEach((s, i) => { if (i && !(s.at > stops[i - 1].at)) err(`sky.gradient_stops: الترتيب غير تصاعدي عند ${s.at}`); if (!/^#[0-9a-fA-F]{6}$/.test(s.color)) err(`sky.gradient_stops: لون غير صالح ${s.color}`); });
|
| 83 |
|
| 84 |
-
console.log(`أخطاء: ${errors.length}
|
| 85 |
-
errors.forEach((e) => console.log(
|
| 86 |
-
warnings.forEach((w) => console.log(
|
| 87 |
process.exit(errors.length ? 1 : 0);
|
|
|
|
| 1 |
#!/usr/bin/env node
|
| 2 |
+
'use strict';
|
| 3 |
+
/* مدقّق اتساق بين fiqh_time_registry و worship_fiqh_registry (ومحاكاة قرارات solar_engine.js).
|
| 4 |
+
الاستعمال: node validate_registries.js [المجلد] — يُرجع رمز خروج 1 عند وجود أخطاء. */
|
| 5 |
+
const fs = require('fs'), path = require('path');
|
| 6 |
+
const dir = process.argv[2] || '.';
|
| 7 |
+
const load = (name) => JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'));
|
| 8 |
const errors = [], warnings = [];
|
| 9 |
const err = (m) => errors.push(m), warn = (m) => warnings.push(m);
|
| 10 |
|
| 11 |
+
const time = load('fiqh_time_registry.json');
|
| 12 |
+
const worship = load('worship_fiqh_registry.json');
|
| 13 |
const profile = time.calculation_profile;
|
| 14 |
+
const boundaryIds = new Set(time.boundaries.map((b) => b.id));
|
| 15 |
+
const aliasIds = new Set(Object.keys(time.aliases || {}));
|
| 16 |
+
const known = (id) => boundaryIds.has(id) || aliasIds.has(id);
|
|
|
|
|
|
|
| 17 |
|
| 18 |
+
/* ---- fiqh_time_registry ---- */
|
| 19 |
+
const seen = new Set();
|
| 20 |
+
for (const b of time.boundaries) { if (seen.has(b.id)) err(`time: معرّف حد مكرر ${b.id}`); seen.add(b.id); }
|
| 21 |
+
for (const id of time.ordering) if (!known(id)) err(`time.ordering: ${id} غير معرّف`);
|
| 22 |
+
for (const b of time.boundaries) if (!time.ordering.includes(b.id)) warn(`time.ordering: الحد ${b.id} غير مرتّب`);
|
| 23 |
+
for (const [id, def] of Object.entries(profile.boundaries)) {
|
| 24 |
+
if (!known(id)) err(`profile.boundaries: ${id} غير موجود في boundaries أو aliases`);
|
| 25 |
+
for (const key of ['boundary', 'from', 'to']) if (def[key] && !known(def[key]) && !profile.boundaries[def[key]]) err(`profile.boundaries.${id}.${key}: ${def[key]} غير معرّف`);
|
| 26 |
+
if (def.op === 'rule_start' && !worship.rules.some((r) => r.id === def.rule_id)) err(`profile.boundaries.${id}: القاعدة ${def.rule_id} غير موجودة في worship`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
}
|
| 28 |
+
for (const [k, v] of Object.entries(profile.relation_bindings || {})) for (const id of [].concat(v)) if (!known(id) && !profile.boundaries[id]) err(`relation_bindings.${k}: ${id} غير معرّف`);
|
| 29 |
+
for (const rid of Object.keys(profile.rule_time_bindings || {})) if (!worship.rules.some((r) => r.id === rid)) err(`rule_time_bindings: القاعدة ${rid} غير موجودة`);
|
| 30 |
+
for (const key of ['time_tolerance_ms', 'derivative_sample_ms', 'scan_step_ms', 'bisect_iterations', 'maximum_iterations', 'transit_iterations', 'noon_bracket_hours', 'half_day_hours', 'dependency_passes', 'longitude_degrees_per_hour'])
|
| 31 |
+
if (!(Number(profile.solar_solver?.[key]) > 0)) err(`solar_solver.${key} مفقود أو غير موجب`);
|
| 32 |
|
| 33 |
+
/* ---- worship_fiqh_registry ---- */
|
| 34 |
+
const ruleIds = new Set();
|
| 35 |
+
for (const r of worship.rules) { if (ruleIds.has(r.id)) err(`worship: قاعدة مكررة ${r.id}`); ruleIds.add(r.id); }
|
| 36 |
+
const estimateIds = new Set(Object.keys(worship.display_estimates || {}));
|
| 37 |
+
for (const r of worship.rules) for (const id of Object.keys(r.window_display_estimates || {})) estimateIds.add(id);
|
| 38 |
+
const refKeys = ['start', 'end', 'display_start', 'outer_end', 'necessity_end', 'preferred_end', 'allowed_to'];
|
| 39 |
+
const checkRef = (where, id) => { if (id && !known(id) && !profile.boundaries[id]) err(`${where}: الحد ${id} غير معرّف في fiqh_time_registry`); };
|
| 40 |
+
for (const rule of worship.rules) {
|
| 41 |
+
for (const sid of rule.sources || []) if (!worship.sources[sid]) err(`rule ${rule.id}: المصدر ${sid} غير معرّف`);
|
| 42 |
+
const scan = (where, o) => { if (!o || typeof o !== 'object') return; for (const k of refKeys) checkRef(`${where}.${k}`, o[k]); for (const k of ['display_estimate_id', 'display_end_estimate_id']) if (o[k] && !estimateIds.has(o[k])) err(`${where}.${k}: التقدير ${o[k]} غير معرّف`); };
|
| 43 |
+
scan(`rule ${rule.id}.common`, rule.common);
|
| 44 |
+
for (const [m, choice] of Object.entries(rule.madhhab || {})) {
|
| 45 |
+
if (!worship.madhhabs[m]) err(`rule ${rule.id}: مذهب غير معرّف ${m}`);
|
| 46 |
+
scan(`rule ${rule.id}.${m}`, choice);
|
| 47 |
+
for (const w of (typeof choice === 'object' && choice.windows) || []) scan(`rule ${rule.id}.${m}.window`, w);
|
| 48 |
+
}
|
| 49 |
+
/* محاكاة قرار solar_engine.periods() لكل مذهب: هل ينتج صفًا؟ */
|
| 50 |
+
const needsCalendar = Boolean(rule.calendar_rule);
|
| 51 |
+
for (const m of Object.keys(worship.madhhabs)) {
|
| 52 |
+
const choice = rule.madhhab?.[m];
|
| 53 |
+
const common = { ...rule.common, ...(typeof choice === 'object' ? choice : {}), ...(profile.rule_time_bindings?.[rule.id] || {}) };
|
| 54 |
+
const windows = (typeof choice === 'object' && choice.windows) || rule.windows || [common];
|
| 55 |
+
for (const w of windows) {
|
| 56 |
+
const startId = w.display_start || common.display_start || w.start || common.start || rule.trigger?.start || profile.relation_bindings?.[w.start_relation || common.start_relation];
|
| 57 |
+
const endId = w.end || common.end || w.outer_end || common.outer_end || w.necessity_end || common.necessity_end || rule.trigger?.end;
|
| 58 |
+
const estimate = estimateIds.has(w.display_estimate_id);
|
| 59 |
+
if (!estimate && (!startId || !endId)) err(`rule ${rule.id} [${m}]: لن يُنتج صفًا (بداية=${startId || '∅'} ، نهاية=${endId || '∅'})${needsCalendar ? ' — قاعدة تقويمية' : ''}`);
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
for (const out of worship.required_time_engine_outputs || []) if (!profile.boundaries[out.id] && !known(out.id)) err(`required_time_engine_outputs: ${out.id} غير معرّف`);
|
| 64 |
+
const used = new Set();
|
| 65 |
+
for (const rule of worship.rules) JSON.stringify(rule, (k, v) => { if (refKeys.includes(k) && typeof v === 'string') used.add(v); return v; });
|
| 66 |
+
for (const id of used) if (known(id) && !(worship.required_time_engine_outputs || []).some((o) => o.id === id) && !profile.boundaries[id] && !aliasIds.has(id) && !time.boundaries.some((b) => b.id === id && b.source !== 'astronomy_engine')) warn(`الحد ${id} مستخدم ولا يظهر في required_time_engine_outputs`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
+
console.log(`أخطاء: ${errors.length} | تحذيرات: ${warnings.length}`);
|
| 69 |
+
errors.forEach((e) => console.log(' ✗ ' + e));
|
| 70 |
+
warnings.forEach((w) => console.log(' ! ' + w));
|
| 71 |
process.exit(errors.length ? 1 : 0);
|
worship_event_engine.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
| 1 |
'use strict';
|
| 2 |
|
| 3 |
// Pure registry scheduler. Solar geometry and religious rules remain in their owners.
|
| 4 |
-
// v2: eclipse search is cached on a day-aligned window (the old key changed every call), the cache is
|
| 5 |
-
// per event, only real eclipse types are searched, penumbral/excluded subtypes are skipped, and the
|
| 6 |
-
// visibility altitude comes from the registry's visibility_rule.
|
| 7 |
globalThis.WorshipEventEngine = (() => {
|
| 8 |
const DAY=86400000,MINUTE=60000;
|
| 9 |
const civil=stamp=>{const d=new Date(stamp);return new Date(d.getUTCFullYear(),d.getUTCMonth(),d.getUTCDate(),12);};
|
|
@@ -62,42 +59,46 @@ globalThis.WorshipEventEngine = (() => {
|
|
| 62 |
return notices.sort((a,b)=>a.at-b.at||b.priority-a.priority);
|
| 63 |
}
|
| 64 |
const eclipseCache=new Map();
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
function visibleInterval(A,body,observer,start,end,minAltitude
|
| 68 |
-
const altitude=t=>{const d=new Date(t),eq=A.Equator(body,d,observer,true,true);return A.Horizon(d,observer,eq.ra,eq.dec,
|
| 69 |
let first=start;
|
| 70 |
-
// Conservative center-above-threshold visibility, solved by the same engine.
|
| 71 |
if(altitude(first)<=minAltitude){const rise=A.SearchAltitude(body,observer,1,new Date(start),(end-start)/DAY,minAltitude);if(!rise)return null;first=rise.date.getTime();}
|
| 72 |
-
const set=A.SearchAltitude(body,observer,-1,new Date(first+
|
| 73 |
const last=set?Math.min(end,set.date.getTime()):end;
|
| 74 |
return last>first?{start:first,end:last}:null;
|
| 75 |
}
|
|
|
|
|
|
|
| 76 |
function eclipses({astronomy,event,location,start,end,A=globalThis.Astronomy}){
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
| 81 |
if(!occurrences){
|
| 82 |
occurrences=[];const observer=new A.Observer(location.lat,location.lng,location.height||0);
|
| 83 |
-
for(const type of astronomy.event_types.filter(t=>t.religious_relation?.practice_id===event.id&&t.enabled!==false
|
|
|
|
|
|
|
|
|
|
| 84 |
try{
|
| 85 |
-
const solar=type.id==='solar_eclipse',
|
| 86 |
-
|
| 87 |
-
let
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
const kind=String(found.kind||'').toLowerCase();
|
| 91 |
-
if(!excluded.includes(kind)){
|
| 92 |
const begin=solar?found.partial_begin.time.date.getTime():peak-found.sd_partial*MINUTE;
|
| 93 |
const finish=solar?found.partial_end.time.date.getTime():peak+found.sd_partial*MINUTE;
|
| 94 |
-
if(finish>=from&&finish>begin){const visible=visibleInterval(A,solar?'Sun':'Moon',observer,begin,finish,
|
| 95 |
}
|
| 96 |
found=solar?A.NextLocalSolarEclipse(found.peak.time,observer):A.NextLunarEclipse(found.peak);
|
| 97 |
}
|
| 98 |
}catch{/* No invented eclipse when ephemeris calculation fails. */}
|
| 99 |
}
|
| 100 |
-
eclipseCache.set(cacheKey,occurrences);if(eclipseCache.size>
|
| 101 |
}
|
| 102 |
const notices=[];
|
| 103 |
for(const occurrence of occurrences){
|
|
|
|
| 1 |
'use strict';
|
| 2 |
|
| 3 |
// Pure registry scheduler. Solar geometry and religious rules remain in their owners.
|
|
|
|
|
|
|
|
|
|
| 4 |
globalThis.WorshipEventEngine = (() => {
|
| 5 |
const DAY=86400000,MINUTE=60000;
|
| 6 |
const civil=stamp=>{const d=new Date(stamp);return new Date(d.getUTCFullYear(),d.getUTCMonth(),d.getUTCDate(),12);};
|
|
|
|
| 59 |
return notices.sort((a,b)=>a.at-b.at||b.priority-a.priority);
|
| 60 |
}
|
| 61 |
const eclipseCache=new Map();
|
| 62 |
+
// Geometric centre altitude: the same convention as Astronomy.SearchAltitude, so the horizon test
|
| 63 |
+
// and the rise/set search agree (the previous version mixed refracted and geometric altitudes).
|
| 64 |
+
function visibleInterval(A,body,observer,start,end,minAltitude,epsilon){
|
| 65 |
+
const altitude=t=>{const d=new Date(t),eq=A.Equator(body,d,observer,true,true);return A.Horizon(d,observer,eq.ra,eq.dec,null).altitude;};
|
| 66 |
let first=start;
|
|
|
|
| 67 |
if(altitude(first)<=minAltitude){const rise=A.SearchAltitude(body,observer,1,new Date(start),(end-start)/DAY,minAltitude);if(!rise)return null;first=rise.date.getTime();}
|
| 68 |
+
const set=A.SearchAltitude(body,observer,-1,new Date(first+epsilon),(end-first)/DAY,minAltitude);
|
| 69 |
const last=set?Math.min(end,set.date.getTime()):end;
|
| 70 |
return last>first?{start:first,end:last}:null;
|
| 71 |
}
|
| 72 |
+
// Scan limits come from astronomy.defaults.eclipse_scan; the visibility threshold and the excluded
|
| 73 |
+
// eclipse kinds come from each event type's religious_relation. Missing data means no notice, never a guess.
|
| 74 |
function eclipses({astronomy,event,location,start,end,A=globalThis.Astronomy}){
|
| 75 |
+
const scan=astronomy?.defaults?.eclipse_scan;
|
| 76 |
+
const complete=scan&&['max_occurrences','lookback_days','cache_limit','epsilon_ms'].every(key=>Number(scan[key])>0);
|
| 77 |
+
if(!A||!location||!event||event.enabled===false||astronomy.enabled===false||!complete)return [];
|
| 78 |
+
// Snap to whole days so the cache survives the per-minute calls of the notice loop.
|
| 79 |
+
const from=Math.floor(start/DAY)*DAY,to=Math.ceil(end/DAY)*DAY;
|
| 80 |
+
const cacheKey=JSON.stringify([location,from,to]);let occurrences=eclipseCache.get(cacheKey);
|
| 81 |
if(!occurrences){
|
| 82 |
occurrences=[];const observer=new A.Observer(location.lat,location.lng,location.height||0);
|
| 83 |
+
for(const type of astronomy.event_types.filter(t=>t.religious_relation?.practice_id===event.id&&t.enabled!==false)){
|
| 84 |
+
const relation=type.religious_relation,rule=relation.visibility_rule;
|
| 85 |
+
if(!rule||!Number.isFinite(rule.min_altitude_deg))continue;
|
| 86 |
+
const excluded=(relation.excluded_subtypes||[]).map(kind=>String(kind).toLowerCase());
|
| 87 |
try{
|
| 88 |
+
const solar=type.id==='solar_eclipse',origin=new Date(from-scan.lookback_days*DAY);
|
| 89 |
+
let found=solar?A.SearchLocalSolarEclipse(origin,observer):A.SearchLunarEclipse(origin);
|
| 90 |
+
for(let i=0;i<scan.max_occurrences;i++){
|
| 91 |
+
const peak=(solar?found.peak.time:found.peak).date.getTime();if(peak>to+DAY)break;
|
| 92 |
+
if(!excluded.includes(String(found.kind).toLowerCase())){
|
|
|
|
|
|
|
| 93 |
const begin=solar?found.partial_begin.time.date.getTime():peak-found.sd_partial*MINUTE;
|
| 94 |
const finish=solar?found.partial_end.time.date.getTime():peak+found.sd_partial*MINUTE;
|
| 95 |
+
if(finish>=from&&finish>begin){const visible=visibleInterval(A,solar?'Sun':'Moon',observer,begin,finish,rule.min_altitude_deg,scan.epsilon_ms);if(visible)occurrences.push({typeId:type.id,kind:String(found.kind).toLowerCase(),peak,...visible});}
|
| 96 |
}
|
| 97 |
found=solar?A.NextLocalSolarEclipse(found.peak.time,observer):A.NextLunarEclipse(found.peak);
|
| 98 |
}
|
| 99 |
}catch{/* No invented eclipse when ephemeris calculation fails. */}
|
| 100 |
}
|
| 101 |
+
eclipseCache.set(cacheKey,occurrences);if(eclipseCache.size>scan.cache_limit)eclipseCache.delete(eclipseCache.keys().next().value);
|
| 102 |
}
|
| 103 |
const notices=[];
|
| 104 |
for(const occurrence of occurrences){
|
worship_fiqh_registry.json
CHANGED
|
@@ -1,618 +1,651 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
}
|
| 54 |
-
},
|
| 55 |
-
"sources": [
|
| 56 |
-
"hanafi_asr",
|
| 57 |
-
"asr_comparison"
|
| 58 |
-
]
|
| 59 |
-
},
|
| 60 |
-
{
|
| 61 |
-
"id": "asr",
|
| 62 |
-
"category": "obligatory_prayer",
|
| 63 |
-
"common": {
|
| 64 |
-
"end": "sunset"
|
| 65 |
-
},
|
| 66 |
-
"madhhab": {
|
| 67 |
-
"hanafi": {
|
| 68 |
-
"start": "asr_shadow_2",
|
| 69 |
-
"variant": "أبو يوسف ومحمد ورواية عن أبي حنيفة: asr_shadow_1",
|
| 70 |
-
"late": "يكره التأخير إلى تغير/اصفرار الشمس بلا عذر"
|
| 71 |
-
},
|
| 72 |
-
"maliki": {
|
| 73 |
-
"start": "asr_shadow_1",
|
| 74 |
-
"note": "يفصل بين الاختياري والضروري"
|
| 75 |
-
},
|
| 76 |
-
"shafii": {
|
| 77 |
-
"start": "asr_shadow_1",
|
| 78 |
-
"note": "توجد مراتب للوقت"
|
| 79 |
-
},
|
| 80 |
-
"hanbali": {
|
| 81 |
-
"start": "asr_shadow_1",
|
| 82 |
-
"note": "وقت اختيار ثم ضرورة إلى الغروب"
|
| 83 |
-
}
|
| 84 |
-
},
|
| 85 |
-
"sources": [
|
| 86 |
-
"hanafi_asr",
|
| 87 |
-
"asr_comparison"
|
| 88 |
-
]
|
| 89 |
-
},
|
| 90 |
-
{
|
| 91 |
-
"id": "maghrib",
|
| 92 |
-
"category": "obligatory_prayer",
|
| 93 |
-
"common": {
|
| 94 |
-
"start": "sunset"
|
| 95 |
-
},
|
| 96 |
-
"madhhab": {
|
| 97 |
-
"hanafi": {
|
| 98 |
-
"end": "isha_entry_hanafi"
|
| 99 |
-
},
|
| 100 |
-
"maliki": {
|
| 101 |
-
"end": "red_twilight_end"
|
| 102 |
-
},
|
| 103 |
-
"shafii": {
|
| 104 |
-
"end": "red_twilight_end",
|
| 105 |
-
"note": "يوجد تفصيل قديم/جديد في المذهب؛ تحفظ الروايات ولا تختزل"
|
| 106 |
-
},
|
| 107 |
-
"hanbali": {
|
| 108 |
-
"end": "red_twilight_end"
|
| 109 |
-
}
|
| 110 |
-
},
|
| 111 |
-
"sources": [
|
| 112 |
-
"maghrib_shafii",
|
| 113 |
-
"isha_twilight"
|
| 114 |
-
]
|
| 115 |
-
},
|
| 116 |
-
{
|
| 117 |
-
"id": "isha_entry",
|
| 118 |
-
"category": "obligatory_prayer",
|
| 119 |
-
"madhhab": {
|
| 120 |
-
"hanafi": {
|
| 121 |
-
"start": "white_twilight_end",
|
| 122 |
-
"variant": "أبو يوسف ومحمد ورواية عن أبي حنيفة: red_twilight_end"
|
| 123 |
-
},
|
| 124 |
-
"maliki": {
|
| 125 |
-
"start": "red_twilight_end"
|
| 126 |
-
},
|
| 127 |
-
"shafii": {
|
| 128 |
-
"start": "red_twilight_end"
|
| 129 |
-
},
|
| 130 |
-
"hanbali": {
|
| 131 |
-
"start": "red_twilight_end"
|
| 132 |
-
}
|
| 133 |
-
},
|
| 134 |
-
"sources": [
|
| 135 |
-
"isha_twilight"
|
| 136 |
-
]
|
| 137 |
-
},
|
| 138 |
-
{
|
| 139 |
-
"id": "isha_periods",
|
| 140 |
-
"category": "obligatory_prayer",
|
| 141 |
-
"madhhab": {
|
| 142 |
-
"hanafi": {
|
| 143 |
-
"outer_end": "next_true_dawn",
|
| 144 |
-
"note": "داخل المذهب مراتب فضيلة قبل ذلك"
|
| 145 |
-
},
|
| 146 |
-
"maliki": {
|
| 147 |
-
"preferred_end": "first_third_of_night",
|
| 148 |
-
"outer_end": "next_true_dawn",
|
| 149 |
-
"note": "تفصيل الاختياري/الضروري يحفظ في profile المذهب"
|
| 150 |
-
},
|
| 151 |
-
"shafii": {
|
| 152 |
-
"preferred_end": "first_third_of_night",
|
| 153 |
-
"outer_end": "next_true_dawn"
|
| 154 |
-
},
|
| 155 |
-
"hanbali": {
|
| 156 |
-
"preferred_end": "first_third_of_night",
|
| 157 |
-
"allowed_to": "islamic_midnight",
|
| 158 |
-
"necessity_end": "next_true_dawn"
|
| 159 |
-
}
|
| 160 |
-
},
|
| 161 |
-
"sources": [
|
| 162 |
-
"isha_end",
|
| 163 |
-
"isha_end_detail"
|
| 164 |
-
]
|
| 165 |
-
},
|
| 166 |
-
{
|
| 167 |
-
"id": "duha",
|
| 168 |
-
"category": "voluntary_prayer",
|
| 169 |
-
"common": {
|
| 170 |
-
"start": "sunrise_clear",
|
| 171 |
-
"end": "solar_noon",
|
| 172 |
-
"ruling": "recommended",
|
| 173 |
-
"best_time": "when_sun_is_high_and_heat_has_increased"
|
| 174 |
-
},
|
| 175 |
-
"madhhab": {
|
| 176 |
-
"hanafi": "recommended",
|
| 177 |
-
"maliki": "recommended",
|
| 178 |
-
"shafii": "emphasized_sunnah",
|
| 179 |
-
"hanbali": "recommended"
|
| 180 |
-
},
|
| 181 |
-
"implementation": "لا +15 دقيقة بعد الشروق ولا -5 قبل الزوال؛ الحدود من الهندسة الشمسية.",
|
| 182 |
-
"sources": [
|
| 183 |
-
"duha"
|
| 184 |
-
]
|
| 185 |
-
},
|
| 186 |
-
{
|
| 187 |
-
"id": "witr",
|
| 188 |
-
"category": "night_prayer",
|
| 189 |
-
"common": {
|
| 190 |
-
"start_relation": "after_isha",
|
| 191 |
-
"end": "next_true_dawn",
|
| 192 |
-
"preferred": "آخر الليل لمن يثق بالاستيقاظ",
|
| 193 |
-
"early_option": "قبل النوم لمن يخشى ألا يستيقظ"
|
| 194 |
-
},
|
| 195 |
-
"sources": [
|
| 196 |
-
"witr"
|
| 197 |
-
]
|
| 198 |
-
},
|
| 199 |
-
{
|
| 200 |
-
"id": "qiyam",
|
| 201 |
-
"category": "night_prayer",
|
| 202 |
-
"common": {
|
| 203 |
-
"start_relation": "after_isha",
|
| 204 |
-
"end": "next_true_dawn",
|
| 205 |
-
"preferred_window": "last_third_start_to_next_true_dawn"
|
| 206 |
-
},
|
| 207 |
-
"sources": [
|
| 208 |
-
"witr",
|
| 209 |
-
"last_third"
|
| 210 |
-
]
|
| 211 |
-
},
|
| 212 |
-
{
|
| 213 |
-
"id": "jumuah",
|
| 214 |
-
"category": "obligatory_prayer",
|
| 215 |
-
"madhhab": {
|
| 216 |
-
"hanafi": {
|
| 217 |
-
"start": "zawal",
|
| 218 |
-
"end_relation": "dhuhr_end"
|
| 219 |
-
},
|
| 220 |
-
"maliki": {
|
| 221 |
-
"start": "zawal",
|
| 222 |
-
"end_relation": "dhuhr_end_with_detail"
|
| 223 |
-
},
|
| 224 |
-
"shafii": {
|
| 225 |
-
"start": "zawal",
|
| 226 |
-
"end_relation": "dhuhr_end"
|
| 227 |
-
},
|
| 228 |
-
"hanbali": {
|
| 229 |
-
"start_variant": "before_zawal_allowed",
|
| 230 |
-
"preferred_display": "after_zawal",
|
| 231 |
-
"end_relation": "asr_entry"
|
| 232 |
-
}
|
| 233 |
-
},
|
| 234 |
-
"sources": [
|
| 235 |
-
"jumuah"
|
| 236 |
-
]
|
| 237 |
-
},
|
| 238 |
-
{
|
| 239 |
-
"id": "after_fajr_nafl_restriction",
|
| 240 |
-
"category": "prayer_restriction",
|
| 241 |
-
"scope": "general_voluntary_prayer",
|
| 242 |
-
"display_policy": "show_without_worship_tracking",
|
| 243 |
-
"madhhab": {
|
| 244 |
-
"hanafi": {
|
| 245 |
-
"activation": "boundary",
|
| 246 |
-
"start": "true_dawn",
|
| 247 |
-
"end": "sunrise",
|
| 248 |
-
"exception": "fajr_sunnah_before_obligatory_prayer"
|
| 249 |
-
},
|
| 250 |
-
"maliki": {
|
| 251 |
-
"activation": "boundary",
|
| 252 |
-
"start": "true_dawn",
|
| 253 |
-
"end": "sunrise",
|
| 254 |
-
"exception": "fajr_sunnah_before_obligatory_prayer"
|
| 255 |
-
},
|
| 256 |
-
"shafii": {
|
| 257 |
-
"activation": "after_prayer",
|
| 258 |
-
"requires": "fajr_prayer_performed",
|
| 259 |
-
"display_start": "fajr",
|
| 260 |
-
"end": "sunrise"
|
| 261 |
-
},
|
| 262 |
-
"hanbali": {
|
| 263 |
-
"activation": "boundary",
|
| 264 |
-
"start": "true_dawn",
|
| 265 |
-
"end": "sunrise",
|
| 266 |
-
"exception": "fajr_sunnah_before_obligatory_prayer",
|
| 267 |
-
"variant": "رواية: يتعلق النهي بأداء صلاة الفجر"
|
| 268 |
-
}
|
| 269 |
-
},
|
| 270 |
-
"critical": "يختلف بدء النهي: عند الحنفية والمالكية والمشهور عند الحنابلة من طلوع الفجر، وعند الشافعية بعد أداء صلاة الفجر. العرض البرتقالي لا يسجل أداء العبادة.",
|
| 271 |
-
"note": "تنتهي هذه الطبقة عند الشروق، ثم تبدأ طبقة النهي الشمسي الأحمر إلى ارتفاع الشمس. الاستثناءات المتعلقة بنوع الصلاة تعرض في تفاصيل الحكم ولا تغيّر الحد الزمني العام بلا دليل خاص.",
|
| 272 |
-
"sources": [
|
| 273 |
-
"post_prayer_prohibition",
|
| 274 |
-
"prohibition_comparative",
|
| 275 |
-
"prohibition_trigger_comparative"
|
| 276 |
-
]
|
| 277 |
-
},
|
| 278 |
-
{
|
| 279 |
-
"id": "after_asr_nafl_restriction",
|
| 280 |
-
"category": "prayer_restriction",
|
| 281 |
-
"scope": "general_voluntary_prayer",
|
| 282 |
-
"display_policy": "conditional_window_without_worship_tracking",
|
| 283 |
-
"common": {
|
| 284 |
-
"activation": "after_prayer",
|
| 285 |
-
"requires": "asr_prayer_performed",
|
| 286 |
-
"display_start": "asr",
|
| 287 |
-
"end": "sunset_approach"
|
| 288 |
-
},
|
| 289 |
-
"madhhab": {
|
| 290 |
-
"hanafi": {
|
| 291 |
-
"activation": "after_prayer",
|
| 292 |
-
"requires": "asr_prayer_performed"
|
| 293 |
-
},
|
| 294 |
-
"maliki": {
|
| 295 |
-
"activation": "after_prayer",
|
| 296 |
-
"requires": "asr_prayer_performed"
|
| 297 |
-
},
|
| 298 |
-
"shafii": {
|
| 299 |
-
"activation": "after_prayer",
|
| 300 |
-
"requires": "asr_prayer_performed"
|
| 301 |
-
},
|
| 302 |
-
"hanbali": {
|
| 303 |
-
"activation": "after_prayer",
|
| 304 |
-
"requires": "asr_prayer_performed"
|
| 305 |
-
}
|
| 306 |
-
},
|
| 307 |
-
"critical": "لا يبدأ الحكم بمجرد دخول وقت العصر، بل بعد أداء صلاة العصر. ولأن التطبيق لا يتتبع أداء الصلاة، تعرض المسطرة نافذة برتقالية مشروطة من دخول العصر، لا حكمًا محققًا على المستخدم.",
|
| 308 |
-
"note": "تنتهي الطبقة المشروطة عند اقتراب الغروب، ثم تظهر طبقة النهي الشمسي الأحمر حتى الغروب. الاستثناءات وذوات الأسباب تختلف بين المذاهب وتبقى في تفاصيل الحكم.",
|
| 309 |
-
"sources": [
|
| 310 |
-
"post_prayer_prohibition",
|
| 311 |
-
"prohibition_comparative"
|
| 312 |
-
]
|
| 313 |
-
},
|
| 314 |
-
{
|
| 315 |
-
"id": "absolute_solar_restrictions",
|
| 316 |
-
"category": "solar_prayer_restriction",
|
| 317 |
-
"scope": "absolute_solar_windows",
|
| 318 |
-
"window_display_estimates": {
|
| 319 |
-
"zawal_display_window": {
|
| 320 |
-
"boundary": "solar_noon",
|
| 321 |
-
"before_minutes": 10,
|
| 322 |
-
"after_minutes": 0,
|
| 323 |
-
"user_choices_before_minutes": [
|
| 324 |
-
10,
|
| 325 |
-
15
|
| 326 |
-
],
|
| 327 |
-
"settings_key": "zawal_before_minutes",
|
| 328 |
-
"label_ar": "نافذة عرض قبيل الزوال",
|
| 329 |
-
"note_ar": "نافذة عرض فقط قبل الزوال: تبدأ قبل الاستواء بالمقدار المختار وتنتهي عند الاستواء. بعد الزوال يدخل وقت الظهر فلا تمتد النافذة بعده. القيمتان 10 و15 خيارا عرض، وليستا حدًّا فلكيًا ولا تحديدًا شرعيًا للمدة؛ الأبحاث المذكورة تقدّر المنطقة القريبة من الزوال عادةً بنحو 5–10 دقائق.",
|
| 330 |
-
"source_id": "zawal_duration_research"
|
| 331 |
-
},
|
| 332 |
-
"zawal_20_minutes": {
|
| 333 |
-
"deprecated_alias_of": "zawal_display_window"
|
| 334 |
-
}
|
| 335 |
-
},
|
| 336 |
-
"madhhab": {
|
| 337 |
-
"hanafi": {
|
| 338 |
-
"windows": [
|
| 339 |
-
{
|
| 340 |
-
"start": "sunrise",
|
| 341 |
-
"end": "sunrise_clear"
|
| 342 |
-
},
|
| 343 |
-
{
|
| 344 |
-
"start": "solar_noon",
|
| 345 |
-
"end": "zawal",
|
| 346 |
-
"display_estimate_id": "zawal_display_window"
|
| 347 |
-
},
|
| 348 |
-
{
|
| 349 |
-
"start": "sunset_approach",
|
| 350 |
-
"end": "sunset"
|
| 351 |
-
}
|
| 352 |
-
],
|
| 353 |
-
"variant": "رُوي عن أبي يوسف الترخيص في الاستواء يوم الجمعة، وليس هو العرض الافتراضي للمذهب هنا."
|
| 354 |
-
},
|
| 355 |
-
"maliki": {
|
| 356 |
-
"windows": [
|
| 357 |
-
{
|
| 358 |
-
"start": "sunrise",
|
| 359 |
-
"end": "sunrise_clear"
|
| 360 |
-
},
|
| 361 |
-
{
|
| 362 |
-
"start": "sunset_approach",
|
| 363 |
-
"end": "sunset"
|
| 364 |
-
}
|
| 365 |
-
],
|
| 366 |
-
"note": "لا تعرض نافذة الاستواء إلى الزوال في الاختيار المالكي."
|
| 367 |
-
},
|
| 368 |
-
"shafii": {
|
| 369 |
-
"windows": [
|
| 370 |
-
{
|
| 371 |
-
"start": "sunrise",
|
| 372 |
-
"end": "sunrise_clear"
|
| 373 |
-
},
|
| 374 |
-
{
|
| 375 |
-
"start": "solar_noon",
|
| 376 |
-
"end": "zawal",
|
| 377 |
-
"exclude_weekdays": [
|
| 378 |
-
"friday"
|
| 379 |
-
],
|
| 380 |
-
"display_estimate_id": "zawal_display_window"
|
| 381 |
-
},
|
| 382 |
-
{
|
| 383 |
-
"start": "sunset_approach",
|
| 384 |
-
"end": "sunset"
|
| 385 |
-
}
|
| 386 |
-
],
|
| 387 |
-
"note": "يستثنى الاستواء يوم الجمعة من العرض وفق المعتمد المسجل في المصدر المقارن."
|
| 388 |
-
},
|
| 389 |
-
"hanbali": {
|
| 390 |
-
"windows": [
|
| 391 |
-
{
|
| 392 |
-
"start": "sunrise",
|
| 393 |
-
"end": "sunrise_clear"
|
| 394 |
-
},
|
| 395 |
-
{
|
| 396 |
-
"start": "solar_noon",
|
| 397 |
-
"end": "zawal",
|
| 398 |
-
"display_estimate_id": "zawal_display_window"
|
| 399 |
-
},
|
| 400 |
-
{
|
| 401 |
-
"start": "sunset_approach",
|
| 402 |
-
"end": "sunset"
|
| 403 |
-
}
|
| 404 |
-
]
|
| 405 |
-
}
|
| 406 |
-
},
|
| 407 |
-
"implementation": "الحدود هندسة شمسية بلا دقائق ثابتة؛ نافذة قبيل الزوال سياسة عرض قبل الاستواء فقط وليست بديلًا عن الحد الفلكي، ويمكن للمستخدم اختيار 10 أو 15 دقيقة.",
|
| 408 |
-
"note": "اختيار النوافذ نفسها مذهبي. تعرض نافذة الزوال بمدة عرض احتياطية قبل الزوال فقط (10 افتراضيًا و15 خيار المستخدم)، مع بيان أن الأبحاث المذكورة تقدر المنطقة الأقرب للزوال عادةً بنحو 5–10 دقائق. أما استثناءات أنواع الصلوات كذوات الأسباب والقضاء والجنازة والطواف فلا تختزل في لون زمني عام، وتعرض في تفاصيل الحكم.",
|
| 409 |
-
"sources": [
|
| 410 |
-
"prohibition_comparative",
|
| 411 |
-
"solar_prohibition",
|
| 412 |
-
"zawal_duration_research"
|
| 413 |
-
]
|
| 414 |
-
},
|
| 415 |
-
{
|
| 416 |
-
"id": "ramadan_fast",
|
| 417 |
-
"category": "obligatory_fasting",
|
| 418 |
-
"common": {
|
| 419 |
-
"start": "true_dawn",
|
| 420 |
-
"end": "sunset"
|
| 421 |
-
},
|
| 422 |
-
"note": "ثبوت بداية الشهر من سلطة التقويم/الرؤية المعتمدة، لا من هذا الملف.",
|
| 423 |
-
"sources": [
|
| 424 |
-
"quran_2_187"
|
| 425 |
-
]
|
| 426 |
-
},
|
| 427 |
-
{
|
| 428 |
-
"id": "monday_thursday_fast",
|
| 429 |
-
"category": "recommended_fasting",
|
| 430 |
-
"common": {
|
| 431 |
-
"start": "true_dawn",
|
| 432 |
-
"end": "sunset"
|
| 433 |
-
},
|
| 434 |
-
"note": "اختيار اليوم وجدولته من islamic_events_registry.json."
|
| 435 |
}
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
}
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
"hanafi_asr"
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
"
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
},
|
| 483 |
-
"duha": {
|
| 484 |
-
"title": "الموسوعة الفقهية — صلاة الضحى",
|
| 485 |
-
"url": "https://dorar.net/feqhia/1261/"
|
| 486 |
-
},
|
| 487 |
-
"witr": {
|
| 488 |
-
"title": "الموسوعة الفقهية — أفضل وقت للوتر",
|
| 489 |
-
"url": "https://dorar.net/feqhia/1241/"
|
| 490 |
-
},
|
| 491 |
-
"last_third": {
|
| 492 |
-
"title": "صحيح البخاري 1145",
|
| 493 |
-
"url": "https://sunnah.com/bukhari:1145"
|
| 494 |
-
},
|
| 495 |
-
"jumuah": {
|
| 496 |
-
"title": "مذاهب العلماء في وقت الجمعة",
|
| 497 |
-
"url": "https://islamweb.net/ar/fatwa/23917/"
|
| 498 |
-
},
|
| 499 |
-
"post_prayer_prohibition": {
|
| 500 |
-
"title": "صحيح مسلم 827",
|
| 501 |
-
"url": "https://sunnah.com/muslim:827"
|
| 502 |
-
},
|
| 503 |
-
"prohibition_comparative": {
|
| 504 |
-
"title": "بحث مقارن في أوقات النهي",
|
| 505 |
-
"url": "https://islamport.com/l/msl/3529/9.htm"
|
| 506 |
-
},
|
| 507 |
-
"prohibition_trigger_comparative": {
|
| 508 |
-
"title": "بحث مقارن في تعلق نهي الفجر بطلوعه أو بأداء الصلاة",
|
| 509 |
-
"url": "https://islamport.com/l/msl/3529/17.htm"
|
| 510 |
-
},
|
| 511 |
-
"solar_prohibition": {
|
| 512 |
-
"title": "صحيح مسلم 831",
|
| 513 |
-
"url": "https://sunnah.com/muslim:831"
|
| 514 |
-
},
|
| 515 |
-
"zawal_duration_research": {
|
| 516 |
-
"title": "تقدير المدة القريبة من الزوال وبيان أنها غير ثابتة بعشرين دقيقة",
|
| 517 |
-
"url": "https://saadalkhathlan.com/scientific-series/lessons/32181"
|
| 518 |
-
},
|
| 519 |
-
"quran_2_187": {
|
| 520 |
-
"title": "البقرة 187",
|
| 521 |
-
"reference": "Quran 2:187"
|
| 522 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
},
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
"
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
"
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
"
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 552 |
},
|
| 553 |
-
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
"maliki": {
|
| 558 |
-
"ruling": "sunnah_muakkadah"
|
| 559 |
-
},
|
| 560 |
-
"shafii": {
|
| 561 |
-
"ruling": "sunnah_muakkadah"
|
| 562 |
-
},
|
| 563 |
-
"hanbali": {
|
| 564 |
-
"ruling": "fard_kifayah"
|
| 565 |
-
}
|
| 566 |
},
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
|
|
|
| 578 |
},
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
},
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
"id": "iftar",
|
| 591 |
-
"category": "recommended_fasting_meal",
|
| 592 |
-
"status": "proposed_not_consumed",
|
| 593 |
-
"activation": {
|
| 594 |
-
"owner": "islamic_events_registry.json",
|
| 595 |
-
"note_ar": "أيام الصيام فقط."
|
| 596 |
},
|
| 597 |
-
|
| 598 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
},
|
| 600 |
-
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
"id": "eclipse_prayer",
|
| 605 |
-
"category": "occasional_prayer",
|
| 606 |
-
"status": "proposed_not_consumed",
|
| 607 |
-
"time_source": {
|
| 608 |
-
"owner": "astronomy_events_registry.json",
|
| 609 |
-
"practice_id": "eclipse_prayer",
|
| 610 |
-
"note_ar": "وقتها من محرك الكسوف والخسوف المحلي (الجزء المرئي فقط) ولا يُحسب من هذا الملف."
|
| 611 |
},
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
|
| 615 |
}
|
|
|
|
| 616 |
}
|
| 617 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 618 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"schema_name": "islamic_clock_worship_fiqh_registry",
|
| 3 |
+
"schema_version": "1.3.0",
|
| 4 |
+
"registry_id": "worship_fiqh",
|
| 5 |
+
"project": "ساعة المسلم / الخط الزمني الروحي",
|
| 6 |
+
"language": "ar",
|
| 7 |
+
"direction": "rtl",
|
| 8 |
+
"status": "researched_v2_madhhab_restriction_windows",
|
| 9 |
+
"scope_ar": "أحكام العبادات المرتبطة بالزمن فقط مع الخلاف بين المذاهب الأربعة. لا يملك الحساب الفلكي أو الألوان أو الأيقونات أو منبهات المستخدم.",
|
| 10 |
+
"architecture_contract": {
|
| 11 |
+
"time_geometry_owner": "fiqh_time_registry.json",
|
| 12 |
+
"worship_event_owner": "islamic_events_registry.json",
|
| 13 |
+
"visual_owner": "visual_states_registry.json",
|
| 14 |
+
"user_alarm_owner": "user_time_markers_registry.json",
|
| 15 |
+
"knowledge_owner": "contextual_knowledge_registry.json",
|
| 16 |
+
"no_fixed_solar_minutes": true
|
| 17 |
+
},
|
| 18 |
+
"madhhabs": {
|
| 19 |
+
"hanafi": "الحنفي",
|
| 20 |
+
"maliki": "المالكي",
|
| 21 |
+
"shafii": "الشافعي",
|
| 22 |
+
"hanbali": "الحنبلي"
|
| 23 |
+
},
|
| 24 |
+
"rules": [
|
| 25 |
+
{
|
| 26 |
+
"id": "fajr",
|
| 27 |
+
"category": "obligatory_prayer",
|
| 28 |
+
"common": {
|
| 29 |
+
"start": "true_dawn",
|
| 30 |
+
"end": "sunrise"
|
| 31 |
+
},
|
| 32 |
+
"note": "أصل النافذة مشترك؛ درجات الفضيلة والاختيار تفصيل مذهبي."
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"id": "dhuhr",
|
| 36 |
+
"category": "obligatory_prayer",
|
| 37 |
+
"common": {
|
| 38 |
+
"start": "zawal"
|
| 39 |
+
},
|
| 40 |
+
"madhhab": {
|
| 41 |
+
"hanafi": {
|
| 42 |
+
"end": "asr_shadow_2",
|
| 43 |
+
"variant": "أبو يوسف ومحمد ورواية عن أبي حنيفة: asr_shadow_1"
|
| 44 |
+
},
|
| 45 |
+
"maliki": {
|
| 46 |
+
"end": "asr_shadow_1"
|
| 47 |
+
},
|
| 48 |
+
"shafii": {
|
| 49 |
+
"end": "asr_shadow_1"
|
| 50 |
+
},
|
| 51 |
+
"hanbali": {
|
| 52 |
+
"end": "asr_shadow_1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
}
|
| 54 |
+
},
|
| 55 |
+
"sources": [
|
| 56 |
+
"hanafi_asr",
|
| 57 |
+
"asr_comparison"
|
| 58 |
+
]
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"id": "asr",
|
| 62 |
+
"category": "obligatory_prayer",
|
| 63 |
+
"common": {
|
| 64 |
+
"end": "sunset"
|
| 65 |
+
},
|
| 66 |
+
"madhhab": {
|
| 67 |
+
"hanafi": {
|
| 68 |
+
"start": "asr_shadow_2",
|
| 69 |
+
"variant": "أبو يوسف ومحمد ورواية عن أبي حنيفة: asr_shadow_1",
|
| 70 |
+
"late": "يكره التأخير إلى تغير/اصفرار الشمس بلا عذر"
|
| 71 |
+
},
|
| 72 |
+
"maliki": {
|
| 73 |
+
"start": "asr_shadow_1",
|
| 74 |
+
"note": "يفصل بين الاختياري والضروري"
|
| 75 |
+
},
|
| 76 |
+
"shafii": {
|
| 77 |
+
"start": "asr_shadow_1",
|
| 78 |
+
"note": "توجد مراتب للوقت"
|
| 79 |
+
},
|
| 80 |
+
"hanbali": {
|
| 81 |
+
"start": "asr_shadow_1",
|
| 82 |
+
"note": "وقت اختيار ثم ضرورة إلى الغروب"
|
| 83 |
}
|
| 84 |
+
},
|
| 85 |
+
"sources": [
|
| 86 |
+
"hanafi_asr",
|
| 87 |
+
"asr_comparison"
|
| 88 |
+
]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"id": "maghrib",
|
| 92 |
+
"category": "obligatory_prayer",
|
| 93 |
+
"common": {
|
| 94 |
+
"start": "sunset"
|
| 95 |
+
},
|
| 96 |
+
"madhhab": {
|
| 97 |
+
"hanafi": {
|
| 98 |
+
"end": "isha_entry_hanafi"
|
| 99 |
+
},
|
| 100 |
+
"maliki": {
|
| 101 |
+
"end": "red_twilight_end"
|
| 102 |
+
},
|
| 103 |
+
"shafii": {
|
| 104 |
+
"end": "red_twilight_end",
|
| 105 |
+
"note": "يوجد تفصيل قديم/جديد في المذهب؛ تحفظ الروايات ولا تختزل"
|
| 106 |
+
},
|
| 107 |
+
"hanbali": {
|
| 108 |
+
"end": "red_twilight_end"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
}
|
| 110 |
+
},
|
| 111 |
+
"sources": [
|
| 112 |
+
"maghrib_shafii",
|
| 113 |
+
"isha_twilight"
|
| 114 |
+
]
|
| 115 |
},
|
| 116 |
+
{
|
| 117 |
+
"id": "isha_entry",
|
| 118 |
+
"category": "obligatory_prayer",
|
| 119 |
+
"madhhab": {
|
| 120 |
+
"hanafi": {
|
| 121 |
+
"start": "white_twilight_end",
|
| 122 |
+
"variant": "أبو يوسف ومحمد ورواية عن أبي حنيفة: red_twilight_end"
|
| 123 |
+
},
|
| 124 |
+
"maliki": {
|
| 125 |
+
"start": "red_twilight_end"
|
| 126 |
+
},
|
| 127 |
+
"shafii": {
|
| 128 |
+
"start": "red_twilight_end"
|
| 129 |
+
},
|
| 130 |
+
"hanbali": {
|
| 131 |
+
"start": "red_twilight_end"
|
| 132 |
+
}
|
| 133 |
+
},
|
| 134 |
+
"sources": [
|
| 135 |
+
"isha_twilight"
|
| 136 |
+
]
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"id": "isha_periods",
|
| 140 |
+
"category": "obligatory_prayer",
|
| 141 |
+
"madhhab": {
|
| 142 |
+
"hanafi": {
|
| 143 |
+
"outer_end": "next_true_dawn",
|
| 144 |
+
"note": "داخل المذهب مراتب فضيلة قبل ذلك"
|
| 145 |
+
},
|
| 146 |
+
"maliki": {
|
| 147 |
+
"preferred_end": "first_third_of_night",
|
| 148 |
+
"outer_end": "next_true_dawn",
|
| 149 |
+
"note": "تفصيل الاختياري/الضروري يحفظ في profile المذهب"
|
| 150 |
+
},
|
| 151 |
+
"shafii": {
|
| 152 |
+
"preferred_end": "first_third_of_night",
|
| 153 |
+
"outer_end": "next_true_dawn"
|
| 154 |
+
},
|
| 155 |
+
"hanbali": {
|
| 156 |
+
"preferred_end": "first_third_of_night",
|
| 157 |
+
"allowed_to": "islamic_midnight",
|
| 158 |
+
"necessity_end": "next_true_dawn"
|
| 159 |
+
}
|
| 160 |
+
},
|
| 161 |
+
"sources": [
|
| 162 |
+
"isha_end",
|
| 163 |
+
"isha_end_detail"
|
| 164 |
+
]
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"id": "duha",
|
| 168 |
+
"category": "voluntary_prayer",
|
| 169 |
+
"common": {
|
| 170 |
+
"start": "sunrise_clear",
|
| 171 |
+
"end": "solar_noon",
|
| 172 |
+
"ruling": "recommended",
|
| 173 |
+
"best_time": "when_sun_is_high_and_heat_has_increased"
|
| 174 |
+
},
|
| 175 |
+
"madhhab": {
|
| 176 |
+
"hanafi": "recommended",
|
| 177 |
+
"maliki": "recommended",
|
| 178 |
+
"shafii": "emphasized_sunnah",
|
| 179 |
+
"hanbali": "recommended"
|
| 180 |
+
},
|
| 181 |
+
"implementation": "لا +15 دقيقة بعد الشروق ولا -5 قبل الزوال؛ الحدود من الهندسة الشمسية.",
|
| 182 |
+
"sources": [
|
| 183 |
+
"duha"
|
| 184 |
+
],
|
| 185 |
+
"display_option_note": "يستطيع المحرك إنهاء الضحى قبيل الزوال بإضافة display_end_estimate_id = zawal_pre_noon لمن يقول بالنهي وقت الاستواء (الحنفية والشافعية والحنابلة)، ولا يناسب المالكية. يُترك لقرار شرعي."
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"id": "witr",
|
| 189 |
+
"category": "night_prayer",
|
| 190 |
+
"common": {
|
| 191 |
+
"start_relation": "after_isha",
|
| 192 |
+
"end": "next_true_dawn",
|
| 193 |
+
"preferred": "آخر الليل لمن يثق بالاستيقاظ",
|
| 194 |
+
"early_option": "قبل النوم لمن يخشى ألا يستيقظ"
|
| 195 |
+
},
|
| 196 |
+
"sources": [
|
| 197 |
+
"witr"
|
| 198 |
+
]
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"id": "qiyam",
|
| 202 |
+
"category": "night_prayer",
|
| 203 |
+
"common": {
|
| 204 |
+
"start_relation": "after_isha",
|
| 205 |
+
"end": "next_true_dawn",
|
| 206 |
+
"preferred_window": "last_third_start_to_next_true_dawn"
|
| 207 |
+
},
|
| 208 |
+
"sources": [
|
| 209 |
+
"witr",
|
| 210 |
+
"last_third"
|
| 211 |
+
]
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"id": "jumuah",
|
| 215 |
+
"category": "obligatory_prayer",
|
| 216 |
+
"madhhab": {
|
| 217 |
+
"hanafi": {
|
| 218 |
+
"start": "zawal",
|
| 219 |
+
"end_relation": "dhuhr_end",
|
| 220 |
+
"end": "asr"
|
| 221 |
+
},
|
| 222 |
+
"maliki": {
|
| 223 |
+
"start": "zawal",
|
| 224 |
+
"end_relation": "dhuhr_end_with_detail",
|
| 225 |
+
"end": "asr"
|
| 226 |
+
},
|
| 227 |
+
"shafii": {
|
| 228 |
+
"start": "zawal",
|
| 229 |
+
"end_relation": "dhuhr_end",
|
| 230 |
+
"end": "asr"
|
| 231 |
+
},
|
| 232 |
+
"hanbali": {
|
| 233 |
+
"start_variant": "before_zawal_allowed",
|
| 234 |
+
"preferred_display": "after_zawal",
|
| 235 |
+
"end_relation": "asr_entry",
|
| 236 |
+
"start": "zawal",
|
| 237 |
+
"end": "asr"
|
| 238 |
+
}
|
| 239 |
+
},
|
| 240 |
+
"sources": [
|
| 241 |
+
"jumuah"
|
| 242 |
+
],
|
| 243 |
+
"calendar_rule": {
|
| 244 |
+
"type": "weekly",
|
| 245 |
+
"weekday": "friday"
|
| 246 |
+
},
|
| 247 |
+
"implementation_note": "end_relation الأصلية تبقى للتوثيق؛ end صريح لأن asr يُحل حسب المذهب (rule_start). عند الحنابلة start=zawal هو العرض المفضَّل، ويبقى start_variant للتجويز قبل الزوال."
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"id": "after_fajr_nafl_restriction",
|
| 251 |
+
"category": "prayer_restriction",
|
| 252 |
+
"scope": "general_voluntary_prayer",
|
| 253 |
+
"display_policy": "show_without_worship_tracking",
|
| 254 |
+
"madhhab": {
|
| 255 |
+
"hanafi": {
|
| 256 |
+
"activation": "boundary",
|
| 257 |
+
"start": "true_dawn",
|
| 258 |
+
"end": "sunrise",
|
| 259 |
+
"exception": "fajr_sunnah_before_obligatory_prayer"
|
| 260 |
+
},
|
| 261 |
+
"maliki": {
|
| 262 |
+
"activation": "boundary",
|
| 263 |
+
"start": "true_dawn",
|
| 264 |
+
"end": "sunrise",
|
| 265 |
+
"exception": "fajr_sunnah_before_obligatory_prayer"
|
| 266 |
+
},
|
| 267 |
+
"shafii": {
|
| 268 |
+
"activation": "after_prayer",
|
| 269 |
+
"requires": "fajr_prayer_performed",
|
| 270 |
+
"display_start": "fajr",
|
| 271 |
+
"end": "sunrise"
|
| 272 |
+
},
|
| 273 |
+
"hanbali": {
|
| 274 |
+
"activation": "boundary",
|
| 275 |
+
"start": "true_dawn",
|
| 276 |
+
"end": "sunrise",
|
| 277 |
+
"exception": "fajr_sunnah_before_obligatory_prayer",
|
| 278 |
+
"variant": "رواية: يتعلق النهي بأداء صلاة الفجر"
|
| 279 |
+
}
|
| 280 |
+
},
|
| 281 |
+
"critical": "يختلف بدء النهي: عند الحنفية والمالكية والمشهور عند الحنابلة من طلوع الفجر، وعند الشافعية بعد أداء صلاة الفجر. العرض البرتقالي لا يسجل أداء العبادة.",
|
| 282 |
+
"note": "تنتهي هذه الطبقة عند الشروق، ثم تبدأ طبقة النهي الشمسي الأحمر إلى ارتفاع الشمس. الاستثناءات المتعلقة بنوع الصلاة تعرض في تفاصيل الحكم ولا تغيّر الحد الزمني العام بلا دليل خاص.",
|
| 283 |
+
"sources": [
|
| 284 |
+
"post_prayer_prohibition",
|
| 285 |
+
"prohibition_comparative",
|
| 286 |
+
"prohibition_trigger_comparative"
|
| 287 |
+
]
|
| 288 |
+
},
|
| 289 |
+
{
|
| 290 |
+
"id": "after_asr_nafl_restriction",
|
| 291 |
+
"category": "prayer_restriction",
|
| 292 |
+
"scope": "general_voluntary_prayer",
|
| 293 |
+
"display_policy": "conditional_window_without_worship_tracking",
|
| 294 |
+
"common": {
|
| 295 |
+
"activation": "after_prayer",
|
| 296 |
+
"requires": "asr_prayer_performed",
|
| 297 |
+
"display_start": "asr",
|
| 298 |
+
"end": "sunset_approach"
|
| 299 |
+
},
|
| 300 |
+
"madhhab": {
|
| 301 |
+
"hanafi": {
|
| 302 |
+
"activation": "after_prayer",
|
| 303 |
+
"requires": "asr_prayer_performed"
|
| 304 |
+
},
|
| 305 |
+
"maliki": {
|
| 306 |
+
"activation": "after_prayer",
|
| 307 |
+
"requires": "asr_prayer_performed"
|
| 308 |
+
},
|
| 309 |
+
"shafii": {
|
| 310 |
+
"activation": "after_prayer",
|
| 311 |
+
"requires": "asr_prayer_performed"
|
| 312 |
+
},
|
| 313 |
+
"hanbali": {
|
| 314 |
+
"activation": "after_prayer",
|
| 315 |
+
"requires": "asr_prayer_performed"
|
| 316 |
+
}
|
| 317 |
+
},
|
| 318 |
+
"critical": "لا يبدأ الحكم بمجرد دخول وقت العصر، بل بعد أداء صلاة العصر. ولأن التطبيق لا يتتبع أداء الصلاة، تعرض المسطرة نافذة برتقالية مشروطة من دخول العصر، لا حكمًا محققًا على المستخدم.",
|
| 319 |
+
"note": "تنتهي الطبقة المشروطة عند اقتراب الغروب، ثم تظهر طبقة النهي الشمسي الأحمر حتى الغروب. الاستثناءات وذوات الأسباب تختلف بين المذاهب وتبقى في تفاصيل الحكم.",
|
| 320 |
+
"sources": [
|
| 321 |
+
"post_prayer_prohibition",
|
| 322 |
+
"prohibition_comparative"
|
| 323 |
+
]
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"id": "absolute_solar_restrictions",
|
| 327 |
+
"category": "solar_prayer_restriction",
|
| 328 |
+
"scope": "absolute_solar_windows",
|
| 329 |
+
"madhhab": {
|
| 330 |
+
"hanafi": {
|
| 331 |
+
"windows": [
|
| 332 |
+
{
|
| 333 |
+
"start": "sunrise",
|
| 334 |
+
"end": "sunrise_clear"
|
| 335 |
},
|
| 336 |
+
{
|
| 337 |
+
"start": "solar_noon",
|
| 338 |
+
"end": "zawal",
|
| 339 |
+
"display_estimate_id": "zawal_pre_noon"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
},
|
| 341 |
+
{
|
| 342 |
+
"start": "sunset_approach",
|
| 343 |
+
"end": "sunset"
|
| 344 |
+
}
|
| 345 |
+
],
|
| 346 |
+
"variant": "رُوي عن أبي يوسف الترخيص في الاستواء يوم الجمعة، وليس هو العرض الافتراضي للمذهب هنا."
|
| 347 |
+
},
|
| 348 |
+
"maliki": {
|
| 349 |
+
"windows": [
|
| 350 |
+
{
|
| 351 |
+
"start": "sunrise",
|
| 352 |
+
"end": "sunrise_clear"
|
| 353 |
},
|
| 354 |
+
{
|
| 355 |
+
"start": "sunset_approach",
|
| 356 |
+
"end": "sunset"
|
| 357 |
+
}
|
| 358 |
+
],
|
| 359 |
+
"note": "لا تعرض نافذة الاستواء إلى الزوال في الاختيار المالكي."
|
| 360 |
+
},
|
| 361 |
+
"shafii": {
|
| 362 |
+
"windows": [
|
| 363 |
+
{
|
| 364 |
+
"start": "sunrise",
|
| 365 |
+
"end": "sunrise_clear"
|
| 366 |
},
|
| 367 |
+
{
|
| 368 |
+
"start": "solar_noon",
|
| 369 |
+
"end": "zawal",
|
| 370 |
+
"exclude_weekdays": [
|
| 371 |
+
"friday"
|
| 372 |
+
],
|
| 373 |
+
"display_estimate_id": "zawal_pre_noon"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
},
|
| 375 |
+
{
|
| 376 |
+
"start": "sunset_approach",
|
| 377 |
+
"end": "sunset"
|
| 378 |
+
}
|
| 379 |
+
],
|
| 380 |
+
"note": "يستثنى الاستواء يوم الجمعة من العرض وفق المعتمد المسجل في المصدر المقارن."
|
| 381 |
+
},
|
| 382 |
+
"hanbali": {
|
| 383 |
+
"windows": [
|
| 384 |
+
{
|
| 385 |
+
"start": "sunrise",
|
| 386 |
+
"end": "sunrise_clear"
|
| 387 |
},
|
| 388 |
+
{
|
| 389 |
+
"start": "solar_noon",
|
| 390 |
+
"end": "zawal",
|
| 391 |
+
"display_estimate_id": "zawal_pre_noon"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
},
|
| 393 |
+
{
|
| 394 |
+
"start": "sunset_approach",
|
| 395 |
+
"end": "sunset"
|
| 396 |
}
|
| 397 |
+
]
|
| 398 |
}
|
| 399 |
+
},
|
| 400 |
+
"implementation": "الحدود هندسة شمسية بلا دقائق ثابتة؛ نافذة النهي قبيل الزوال (zawal_pre_noon) سياسة عرض تقديرية تُقرأ من display_estimates وليست بديلًا عن الحد الفلكي.",
|
| 401 |
+
"note": "اختيار النوافذ نفسها مذهبي. تعرض نافذة الزوال قبل الزوال فقط (10 دقائق افتراضيًا، والخيار 15) لأن ما بعد الزوال وقت جواز الصلاة، مع بيان أن الأبحاث المذكورة تقدر المنطقة الأقرب للزوال عادةً بنحو 5–10 دقائق. أما استثناءات أنواع الصلوات كذوات الأسباب والقضاء والجنازة والطواف فلا تختزل في لون زمني عام، وتعرض في تفاصيل الحكم.",
|
| 402 |
+
"sources": [
|
| 403 |
+
"prohibition_comparative",
|
| 404 |
+
"solar_prohibition",
|
| 405 |
+
"zawal_duration_research"
|
| 406 |
+
]
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"id": "eid_fitr_prayer",
|
| 410 |
+
"category": "occasional_prayer",
|
| 411 |
+
"calendar_rule": {
|
| 412 |
+
"calendar": "hijri",
|
| 413 |
+
"month": 10,
|
| 414 |
+
"day": 1,
|
| 415 |
+
"requires_month_confirmation": true
|
| 416 |
+
},
|
| 417 |
+
"common": {
|
| 418 |
+
"start": "sunrise_clear",
|
| 419 |
+
"end": "solar_noon"
|
| 420 |
+
},
|
| 421 |
+
"note": "من ارتفاع الشمس قدر رمح إلى قبيل الزوال. عند الشافعية يدخل وقتها من طلوع الشمس والأفضل بعد ارتفاعها. الحد الأعلى هو الزوال، وsolar_noon يقابله هنا بلا هامش.",
|
| 422 |
+
"research_status": "added_pending_scholar_review",
|
| 423 |
+
"sources": []
|
| 424 |
+
},
|
| 425 |
+
{
|
| 426 |
+
"id": "eid_adha_prayer",
|
| 427 |
+
"category": "occasional_prayer",
|
| 428 |
+
"calendar_rule": {
|
| 429 |
+
"calendar": "hijri",
|
| 430 |
+
"month": 12,
|
| 431 |
+
"day": 10,
|
| 432 |
+
"requires_month_confirmation": true
|
| 433 |
+
},
|
| 434 |
+
"common": {
|
| 435 |
+
"start": "sunrise_clear",
|
| 436 |
+
"end": "solar_noon"
|
| 437 |
+
},
|
| 438 |
+
"note": "يُستحب تعجيلها في الأضحى. نفس حدود صلاة عيد الفطر مع بقاء الاختلاف في الأفضلية.",
|
| 439 |
+
"research_status": "added_pending_scholar_review",
|
| 440 |
+
"sources": []
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"id": "friday_response_hour",
|
| 444 |
+
"category": "recommended_time",
|
| 445 |
+
"calendar_rule": {
|
| 446 |
+
"type": "weekly",
|
| 447 |
+
"weekday": "friday"
|
| 448 |
+
},
|
| 449 |
+
"display_policy": "information_only_without_worship_tracking",
|
| 450 |
+
"common": {
|
| 451 |
+
"start": "last_daylight_hour_start",
|
| 452 |
+
"end": "sunset"
|
| 453 |
+
},
|
| 454 |
+
"note": "يُعرض آخر جزء من نهار الجمعة (اثنا عشر جزءًا للنهار من الشروق إلى الغروب). ويرى كثير من العلماء أنها تمتد من العصر إلى الغروب، وقيل: من جلوس الإمام إلى انقضاء الصلاة. الخلاف يبقى في تفاصيل الحكم، والنافذة معلومة لا ادعاء.",
|
| 455 |
+
"research_status": "added_pending_scholar_review",
|
| 456 |
+
"sources": []
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"id": "ramadan_fast",
|
| 460 |
+
"category": "obligatory_fasting",
|
| 461 |
+
"common": {
|
| 462 |
+
"start": "true_dawn",
|
| 463 |
+
"end": "sunset"
|
| 464 |
+
},
|
| 465 |
+
"note": "ثبوت بداية الشهر من سلطة التقويم/الرؤية المعتمدة، لا من هذا الملف.",
|
| 466 |
+
"sources": [
|
| 467 |
+
"quran_2_187"
|
| 468 |
+
]
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"id": "monday_thursday_fast",
|
| 472 |
+
"category": "recommended_fasting",
|
| 473 |
+
"common": {
|
| 474 |
+
"start": "true_dawn",
|
| 475 |
+
"end": "sunset"
|
| 476 |
+
},
|
| 477 |
+
"note": "اختيار اليوم وجدولته من islamic_events_registry.json."
|
| 478 |
+
}
|
| 479 |
+
],
|
| 480 |
+
"required_time_engine_outputs": [
|
| 481 |
+
{
|
| 482 |
+
"id": "asr_shadow_1",
|
| 483 |
+
"type": "shadow_factor",
|
| 484 |
+
"factor": 1,
|
| 485 |
+
"exclude_noon_shadow": true
|
| 486 |
+
},
|
| 487 |
+
{
|
| 488 |
+
"id": "asr_shadow_2",
|
| 489 |
+
"type": "shadow_factor",
|
| 490 |
+
"factor": 2,
|
| 491 |
+
"exclude_noon_shadow": true
|
| 492 |
+
},
|
| 493 |
+
{
|
| 494 |
+
"id": "first_third_of_night",
|
| 495 |
+
"type": "derived_night_fraction",
|
| 496 |
+
"fraction": "1/3",
|
| 497 |
+
"from": "sunset",
|
| 498 |
+
"to": "next_true_dawn"
|
| 499 |
+
},
|
| 500 |
+
{
|
| 501 |
+
"id": "red_twilight_end",
|
| 502 |
+
"type": "solar_altitude"
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"id": "white_twilight_end",
|
| 506 |
+
"type": "solar_altitude"
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"id": "islamic_midnight",
|
| 510 |
+
"type": "derived_night_fraction",
|
| 511 |
+
"fraction": "1/2",
|
| 512 |
+
"from": "sunset",
|
| 513 |
+
"to": "next_true_dawn"
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"id": "last_third_start",
|
| 517 |
+
"type": "derived_night_fraction",
|
| 518 |
+
"fraction": "2/3",
|
| 519 |
+
"from": "sunset",
|
| 520 |
+
"to": "next_true_dawn"
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"id": "sunrise_clear",
|
| 524 |
+
"type": "solar_altitude"
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"id": "sunset_approach",
|
| 528 |
+
"type": "solar_altitude"
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"id": "solar_noon",
|
| 532 |
+
"type": "solar_transit"
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"id": "zawal",
|
| 536 |
+
"type": "solar_transition"
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"id": "last_daylight_hour_start",
|
| 540 |
+
"type": "derived_day_fraction",
|
| 541 |
+
"fraction": "11/12",
|
| 542 |
+
"from": "sunrise",
|
| 543 |
+
"to": "sunset"
|
| 544 |
+
}
|
| 545 |
+
],
|
| 546 |
+
"sources": {
|
| 547 |
+
"hanafi_asr": {
|
| 548 |
+
"title": "نقول حنفية في المثل والمثلين",
|
| 549 |
+
"url": "https://islamqa.org/hanafi/darul-iftaa-chicago/271053/"
|
| 550 |
+
},
|
| 551 |
+
"asr_comparison": {
|
| 552 |
+
"title": "الفرق بين الحنفية والجمهور في أول العصر",
|
| 553 |
+
"url": "https://islamqa.info/ar/answers/220820"
|
| 554 |
+
},
|
| 555 |
+
"maghrib_shafii": {
|
| 556 |
+
"title": "دائرة الإفتاء الأردنية — وقت المغرب",
|
| 557 |
+
"url": "https://aliftaa.jo/fatwa/3399/CatQuestion.aspx?Id=133"
|
| 558 |
+
},
|
| 559 |
+
"isha_twilight": {
|
| 560 |
+
"title": "الموسوعة الفقهية — الشفق ووقت العشاء",
|
| 561 |
+
"url": "https://dorar.net/feqhia/846/"
|
| 562 |
+
},
|
| 563 |
+
"isha_end": {
|
| 564 |
+
"title": "وقت خروج العشاء في المذاهب الأربعة",
|
| 565 |
+
"url": "https://www.islamweb.org/ar/fatwa/71957/"
|
| 566 |
+
},
|
| 567 |
+
"isha_end_detail": {
|
| 568 |
+
"title": "تفصيل آخر وقت العشاء",
|
| 569 |
+
"url": "https://www.alqayim.org/ar/fatwa/1971"
|
| 570 |
+
},
|
| 571 |
+
"duha": {
|
| 572 |
+
"title": "الموسوعة الفقهية — صلاة الضحى",
|
| 573 |
+
"url": "https://dorar.net/feqhia/1261/"
|
| 574 |
+
},
|
| 575 |
+
"witr": {
|
| 576 |
+
"title": "الموسوعة الفقهية — أفضل وقت للوتر",
|
| 577 |
+
"url": "https://dorar.net/feqhia/1241/"
|
| 578 |
+
},
|
| 579 |
+
"last_third": {
|
| 580 |
+
"title": "صحيح البخاري 1145",
|
| 581 |
+
"url": "https://sunnah.com/bukhari:1145"
|
| 582 |
+
},
|
| 583 |
+
"jumuah": {
|
| 584 |
+
"title": "مذاهب العلماء في وقت الجمعة",
|
| 585 |
+
"url": "https://islamweb.net/ar/fatwa/23917/"
|
| 586 |
+
},
|
| 587 |
+
"post_prayer_prohibition": {
|
| 588 |
+
"title": "صحيح مسلم 827",
|
| 589 |
+
"url": "https://sunnah.com/muslim:827"
|
| 590 |
+
},
|
| 591 |
+
"prohibition_comparative": {
|
| 592 |
+
"title": "بحث مقارن في أوقات النهي",
|
| 593 |
+
"url": "https://islamport.com/l/msl/3529/9.htm"
|
| 594 |
+
},
|
| 595 |
+
"prohibition_trigger_comparative": {
|
| 596 |
+
"title": "بحث مقارن في تعلق نهي الفجر بطلوعه أو بأداء الصلاة",
|
| 597 |
+
"url": "https://islamport.com/l/msl/3529/17.htm"
|
| 598 |
+
},
|
| 599 |
+
"solar_prohibition": {
|
| 600 |
+
"title": "صحيح مسلم 831",
|
| 601 |
+
"url": "https://sunnah.com/muslim:831"
|
| 602 |
+
},
|
| 603 |
+
"zawal_duration_research": {
|
| 604 |
+
"title": "تقدير المدة القريبة من الزوال وبيان أنها غير ثابتة بعشرين دقيقة",
|
| 605 |
+
"url": "https://saadalkhathlan.com/scientific-series/lessons/32181"
|
| 606 |
+
},
|
| 607 |
+
"quran_2_187": {
|
| 608 |
+
"title": "البقرة 187",
|
| 609 |
+
"reference": "Quran 2:187"
|
| 610 |
+
}
|
| 611 |
+
},
|
| 612 |
+
"validation": {
|
| 613 |
+
"worship_only": true,
|
| 614 |
+
"no_colors": true,
|
| 615 |
+
"no_emoji": true,
|
| 616 |
+
"no_user_alarms": true,
|
| 617 |
+
"no_completion_tracking": true,
|
| 618 |
+
"no_fixed_solar_minute_offsets": true,
|
| 619 |
+
"preserve_madhhab_variants": true,
|
| 620 |
+
"calendar_rules_supported": true,
|
| 621 |
+
"categories_requiring_visual_state": [
|
| 622 |
+
"occasional_prayer",
|
| 623 |
+
"recommended_time"
|
| 624 |
+
],
|
| 625 |
+
"visual_note": "الفئتان occasional_prayer وrecommended_time تحتاجان حالة في visual_states_registry.category_states وإلا تُتجاوز القاعدتان بصمت."
|
| 626 |
+
},
|
| 627 |
+
"research_note": "هذه طبقة بيانات للتطبيق وليست فتوى شخصية. حيث لم تكف المصادر لإغلاق تفصيل مذهبي دقيق، أبقي التفصيل معلّقًا بدل اختراع قيمة.",
|
| 628 |
+
"changelog": [
|
| 629 |
+
"1.3.0: إصلاح jumuah: لم يكن ينتج أي نافذة (نهاية غير محلولة، وبداية الحنبلي مفقودة)؛ أُضيفت start/end وقاعدة تقويم weekly:friday",
|
| 630 |
+
"1.3.0: نافذة الزوال: من مركزة ±10 دقائق حول الاستواء إلى قبيل الزوال فقط (10 دقائق، والخيار 15)، لأن ما بعد الزوال وقت جواز الصلاة",
|
| 631 |
+
"1.3.0: انتقال التقديرات إلى display_estimates العليا ليصل إليها كل من start وend (كانت duha لا ترى إلا العليا)",
|
| 632 |
+
"1.3.0: إضافة صلاة العيدين وساعة الإجابة بعد العصر يوم الجمعة (قيد المراجعة الشرعية)",
|
| 633 |
+
"1.3.0: اكتمال required_time_engine_outputs"
|
| 634 |
+
],
|
| 635 |
+
"display_estimates": {
|
| 636 |
+
"note_ar": "تقديرات عرض احتياطية تُقرأ من محرك الفترات. before_minutes قبل الحد وafter_minutes بعده. allowed_before_minutes هي القيم التي يقبلها خيار المستخدم.",
|
| 637 |
+
"zawal_pre_noon": {
|
| 638 |
+
"boundary": "solar_noon",
|
| 639 |
+
"before_minutes": 10,
|
| 640 |
+
"after_minutes": 0,
|
| 641 |
+
"allowed_before_minutes": [
|
| 642 |
+
10,
|
| 643 |
+
15
|
| 644 |
+
],
|
| 645 |
+
"label_ar": "نافذة عرض النهي قبيل الزوال",
|
| 646 |
+
"note_ar": "النهي عن الصلاة وقت قيام الظهيرة حتى تزول الشمس، فالنافذة قبل الزوال فقط، وما بعده وقت الظهر. المدة تقديرية للعرض: الأبحاث المذكورة تقدّر المنطقة القريبة من الزوال بنحو 5–10 دقائق، وخيار 15 للتحوّط. الحد الفلكي المحسوب يبقى محفوظًا مستقلًا.",
|
| 647 |
+
"source_id": "zawal_duration_research",
|
| 648 |
+
"replaces": "zawal_20_minutes"
|
| 649 |
+
}
|
| 650 |
+
}
|
| 651 |
}
|