OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ****************************************************************************** |
| 3 * Copyright (C) 2003-2010, International Business Machines Corporation |
| 4 * and others. All Rights Reserved. |
| 5 ****************************************************************************** |
| 6 * |
| 7 * File ISLAMCAL.H |
| 8 * |
| 9 * Modification History: |
| 10 * |
| 11 * Date Name Description |
| 12 * 10/14/2003 srl ported from java IslamicCalendar |
| 13 ***************************************************************************** |
| 14 */ |
| 15 |
| 16 #include "islamcal.h" |
| 17 |
| 18 #if !UCONFIG_NO_FORMATTING |
| 19 |
| 20 #include "umutex.h" |
| 21 #include <float.h> |
| 22 #include "gregoimp.h" // Math |
| 23 #include "astro.h" // CalendarAstronomer |
| 24 #include "uhash.h" |
| 25 #include "ucln_in.h" |
| 26 |
| 27 static const UDate HIJRA_MILLIS = -42521587200000.0; // 7/16/622 AD 00:00 |
| 28 |
| 29 // Debugging |
| 30 #ifdef U_DEBUG_ISLAMCAL |
| 31 # include <stdio.h> |
| 32 # include <stdarg.h> |
| 33 static void debug_islamcal_loc(const char *f, int32_t l) |
| 34 { |
| 35 fprintf(stderr, "%s:%d: ", f, l); |
| 36 } |
| 37 |
| 38 static void debug_islamcal_msg(const char *pat, ...) |
| 39 { |
| 40 va_list ap; |
| 41 va_start(ap, pat); |
| 42 vfprintf(stderr, pat, ap); |
| 43 fflush(stderr); |
| 44 } |
| 45 // must use double parens, i.e.: U_DEBUG_ISLAMCAL_MSG(("four is: %d",4)); |
| 46 #define U_DEBUG_ISLAMCAL_MSG(x) {debug_islamcal_loc(__FILE__,__LINE__);debug_isl
amcal_msg x;} |
| 47 #else |
| 48 #define U_DEBUG_ISLAMCAL_MSG(x) |
| 49 #endif |
| 50 |
| 51 |
| 52 // --- The cache -- |
| 53 // cache of months |
| 54 static UMTX astroLock = 0; // pod bay door lock |
| 55 static U_NAMESPACE_QUALIFIER CalendarCache *gMonthCache = NULL; |
| 56 static U_NAMESPACE_QUALIFIER CalendarAstronomer *gIslamicCalendarAstro = NULL; |
| 57 |
| 58 U_CDECL_BEGIN |
| 59 static UBool calendar_islamic_cleanup(void) { |
| 60 if (gMonthCache) { |
| 61 delete gMonthCache; |
| 62 gMonthCache = NULL; |
| 63 } |
| 64 if (gIslamicCalendarAstro) { |
| 65 delete gIslamicCalendarAstro; |
| 66 gIslamicCalendarAstro = NULL; |
| 67 } |
| 68 umtx_destroy(&astroLock); |
| 69 return TRUE; |
| 70 } |
| 71 U_CDECL_END |
| 72 |
| 73 U_NAMESPACE_BEGIN |
| 74 |
| 75 // Implementation of the IslamicCalendar class |
| 76 |
| 77 //------------------------------------------------------------------------- |
| 78 // Constructors... |
| 79 //------------------------------------------------------------------------- |
| 80 |
| 81 const char *IslamicCalendar::getType() const { |
| 82 if(civil==CIVIL) { |
| 83 return "islamic-civil"; |
| 84 } else { |
| 85 return "islamic"; |
| 86 } |
| 87 } |
| 88 |
| 89 Calendar* IslamicCalendar::clone() const { |
| 90 return new IslamicCalendar(*this); |
| 91 } |
| 92 |
| 93 IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECi
vil beCivil) |
| 94 : Calendar(TimeZone::createDefault(), aLocale, success), |
| 95 civil(beCivil) |
| 96 { |
| 97 setTimeInMillis(getNow(), success); // Call this again now that the vtable i
s set up properly. |
| 98 } |
| 99 |
| 100 IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other)
, civil(other.civil) { |
| 101 } |
| 102 |
| 103 IslamicCalendar::~IslamicCalendar() |
| 104 { |
| 105 } |
| 106 |
| 107 /** |
| 108 * Determines whether this object uses the fixed-cycle Islamic civil calendar |
| 109 * or an approximation of the religious, astronomical calendar. |
| 110 * |
| 111 * @param beCivil <code>true</code> to use the civil calendar, |
| 112 * <code>false</code> to use the astronomical calendar. |
| 113 * @draft ICU 2.4 |
| 114 */ |
| 115 void IslamicCalendar::setCivil(ECivil beCivil, UErrorCode &status) |
| 116 { |
| 117 if (civil != beCivil) { |
| 118 // The fields of the calendar will become invalid, because the calendar |
| 119 // rules are different |
| 120 UDate m = getTimeInMillis(status); |
| 121 civil = beCivil; |
| 122 clear(); |
| 123 setTimeInMillis(m, status); |
| 124 } |
| 125 } |
| 126 |
| 127 /** |
| 128 * Returns <code>true</code> if this object is using the fixed-cycle civil |
| 129 * calendar, or <code>false</code> if using the religious, astronomical |
| 130 * calendar. |
| 131 * @draft ICU 2.4 |
| 132 */ |
| 133 UBool IslamicCalendar::isCivil() { |
| 134 return (civil == CIVIL); |
| 135 } |
| 136 |
| 137 //------------------------------------------------------------------------- |
| 138 // Minimum / Maximum access functions |
| 139 //------------------------------------------------------------------------- |
| 140 |
| 141 // Note: Current IslamicCalendar implementation does not work |
| 142 // well with negative years. |
| 143 |
| 144 static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = { |
| 145 // Minimum Greatest Least Maximum |
| 146 // Minimum Maximum |
| 147 { 0, 0, 0, 0}, // ERA |
| 148 { 1, 1, 5000000, 5000000}, // YEAR |
| 149 { 0, 0, 11, 11}, // MONTH |
| 150 { 1, 1, 50, 51}, // WEEK_OF_YEAR |
| 151 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH |
| 152 { 1, 1, 29, 30}, // DAY_OF_MONTH |
| 153 { 1, 1, 354, 355}, // DAY_OF_YEAR |
| 154 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK |
| 155 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH |
| 156 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM |
| 157 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR |
| 158 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY |
| 159 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE |
| 160 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND |
| 161 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND |
| 162 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET |
| 163 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET |
| 164 { 1, 1, 5000000, 5000000}, // YEAR_WOY |
| 165 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL |
| 166 { 1, 1, 5000000, 5000000}, // EXTENDED_YEAR |
| 167 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY |
| 168 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY |
| 169 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH |
| 170 }; |
| 171 |
| 172 /** |
| 173 * @draft ICU 2.4 |
| 174 */ |
| 175 int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType li
mitType) const { |
| 176 return LIMITS[field][limitType]; |
| 177 } |
| 178 |
| 179 //------------------------------------------------------------------------- |
| 180 // Assorted calculation utilities |
| 181 // |
| 182 |
| 183 /** |
| 184 * Determine whether a year is a leap year in the Islamic civil calendar |
| 185 */ |
| 186 UBool IslamicCalendar::civilLeapYear(int32_t year) |
| 187 { |
| 188 return (14 + 11 * year) % 30 < 11; |
| 189 } |
| 190 |
| 191 /** |
| 192 * Return the day # on which the given year starts. Days are counted |
| 193 * from the Hijri epoch, origin 0. |
| 194 */ |
| 195 int32_t IslamicCalendar::yearStart(int32_t year) { |
| 196 if (civil == CIVIL) { |
| 197 return (year-1)*354 + ClockMath::floorDivide((3+11*year),30); |
| 198 } else { |
| 199 return trueMonthStart(12*(year-1)); |
| 200 } |
| 201 } |
| 202 |
| 203 /** |
| 204 * Return the day # on which the given month starts. Days are counted |
| 205 * from the Hijri epoch, origin 0. |
| 206 * |
| 207 * @param year The hijri year |
| 208 * @param year The hijri month, 0-based |
| 209 */ |
| 210 int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const { |
| 211 if (civil == CIVIL) { |
| 212 return (int32_t)uprv_ceil(29.5*month) |
| 213 + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*year),30); |
| 214 } else { |
| 215 return trueMonthStart(12*(year-1) + month); |
| 216 } |
| 217 } |
| 218 |
| 219 /** |
| 220 * Find the day number on which a particular month of the true/lunar |
| 221 * Islamic calendar starts. |
| 222 * |
| 223 * @param month The month in question, origin 0 from the Hijri epoch |
| 224 * |
| 225 * @return The day number on which the given month starts. |
| 226 */ |
| 227 int32_t IslamicCalendar::trueMonthStart(int32_t month) const |
| 228 { |
| 229 UErrorCode status = U_ZERO_ERROR; |
| 230 int32_t start = CalendarCache::get(&gMonthCache, month, status); |
| 231 |
| 232 if (start==0) { |
| 233 // Make a guess at when the month started, using the average length |
| 234 UDate origin = HIJRA_MILLIS |
| 235 + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay; |
| 236 |
| 237 // moonAge will fail due to memory allocation error |
| 238 double age = moonAge(origin, status); |
| 239 if (U_FAILURE(status)) { |
| 240 goto trueMonthStartEnd; |
| 241 } |
| 242 |
| 243 if (age >= 0) { |
| 244 // The month has already started |
| 245 do { |
| 246 origin -= kOneDay; |
| 247 age = moonAge(origin, status); |
| 248 if (U_FAILURE(status)) { |
| 249 goto trueMonthStartEnd; |
| 250 } |
| 251 } while (age >= 0); |
| 252 } |
| 253 else { |
| 254 // Preceding month has not ended yet. |
| 255 do { |
| 256 origin += kOneDay; |
| 257 age = moonAge(origin, status); |
| 258 if (U_FAILURE(status)) { |
| 259 goto trueMonthStartEnd; |
| 260 } |
| 261 } while (age < 0); |
| 262 } |
| 263 start = (int32_t)ClockMath::floorDivide((origin - HIJRA_MILLIS), (double
)kOneDay) + 1; |
| 264 CalendarCache::put(&gMonthCache, month, start, status); |
| 265 } |
| 266 trueMonthStartEnd : |
| 267 if(U_FAILURE(status)) { |
| 268 start = 0; |
| 269 } |
| 270 return start; |
| 271 } |
| 272 |
| 273 /** |
| 274 * Return the "age" of the moon at the given time; this is the difference |
| 275 * in ecliptic latitude between the moon and the sun. This method simply |
| 276 * calls CalendarAstronomer.moonAge, converts to degrees, |
| 277 * and adjusts the result to be in the range [-180, 180]. |
| 278 * |
| 279 * @param time The time at which the moon's age is desired, |
| 280 * in millis since 1/1/1970. |
| 281 */ |
| 282 double IslamicCalendar::moonAge(UDate time, UErrorCode &status) |
| 283 { |
| 284 double age = 0; |
| 285 |
| 286 umtx_lock(&astroLock); |
| 287 if(gIslamicCalendarAstro == NULL) { |
| 288 gIslamicCalendarAstro = new CalendarAstronomer(); |
| 289 if (gIslamicCalendarAstro == NULL) { |
| 290 status = U_MEMORY_ALLOCATION_ERROR; |
| 291 return age; |
| 292 } |
| 293 ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_c
leanup); |
| 294 } |
| 295 gIslamicCalendarAstro->setTime(time); |
| 296 age = gIslamicCalendarAstro->getMoonAge(); |
| 297 umtx_unlock(&astroLock); |
| 298 |
| 299 // Convert to degrees and normalize... |
| 300 age = age * 180 / CalendarAstronomer::PI; |
| 301 if (age > 180) { |
| 302 age = age - 360; |
| 303 } |
| 304 |
| 305 return age; |
| 306 } |
| 307 |
| 308 //---------------------------------------------------------------------- |
| 309 // Calendar framework |
| 310 //---------------------------------------------------------------------- |
| 311 |
| 312 /** |
| 313 * Return the length (in days) of the given month. |
| 314 * |
| 315 * @param year The hijri year |
| 316 * @param year The hijri month, 0-based |
| 317 * @draft ICU 2.4 |
| 318 */ |
| 319 int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont
h) const { |
| 320 |
| 321 int32_t length = 0; |
| 322 |
| 323 if (civil == CIVIL) { |
| 324 length = 29 + (month+1) % 2; |
| 325 if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) { |
| 326 length++; |
| 327 } |
| 328 } else { |
| 329 month = 12*(extendedYear-1) + month; |
| 330 length = trueMonthStart(month+1) - trueMonthStart(month) ; |
| 331 } |
| 332 return length; |
| 333 } |
| 334 |
| 335 /** |
| 336 * Return the number of days in the given Islamic year |
| 337 * @draft ICU 2.4 |
| 338 */ |
| 339 int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const { |
| 340 if (civil == CIVIL) { |
| 341 return 354 + (civilLeapYear(extendedYear) ? 1 : 0); |
| 342 } else { |
| 343 int32_t month = 12*(extendedYear-1); |
| 344 return (trueMonthStart(month + 12) - trueMonthStart(month)); |
| 345 } |
| 346 } |
| 347 |
| 348 //------------------------------------------------------------------------- |
| 349 // Functions for converting from field values to milliseconds.... |
| 350 //------------------------------------------------------------------------- |
| 351 |
| 352 // Return JD of start of given month/year |
| 353 /** |
| 354 * @draft ICU 2.4 |
| 355 */ |
| 356 int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
Bool /* useMonth */) const { |
| 357 return monthStart(eyear, month) + 1948439; |
| 358 } |
| 359 |
| 360 //------------------------------------------------------------------------- |
| 361 // Functions for converting from milliseconds to field values |
| 362 //------------------------------------------------------------------------- |
| 363 |
| 364 /** |
| 365 * @draft ICU 2.4 |
| 366 */ |
| 367 int32_t IslamicCalendar::handleGetExtendedYear() { |
| 368 int32_t year; |
| 369 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) { |
| 370 year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1 |
| 371 } else { |
| 372 year = internalGet(UCAL_YEAR, 1); // Default to year 1 |
| 373 } |
| 374 return year; |
| 375 } |
| 376 |
| 377 /** |
| 378 * Override Calendar to compute several fields specific to the Islamic |
| 379 * calendar system. These are: |
| 380 * |
| 381 * <ul><li>ERA |
| 382 * <li>YEAR |
| 383 * <li>MONTH |
| 384 * <li>DAY_OF_MONTH |
| 385 * <li>DAY_OF_YEAR |
| 386 * <li>EXTENDED_YEAR</ul> |
| 387 * |
| 388 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this |
| 389 * method is called. The getGregorianXxx() methods return Gregorian |
| 390 * calendar equivalents for the given Julian day. |
| 391 * @draft ICU 2.4 |
| 392 */ |
| 393 void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
{ |
| 394 int32_t year, month, dayOfMonth, dayOfYear; |
| 395 UDate startDate; |
| 396 int32_t days = julianDay - 1948440; |
| 397 |
| 398 if (civil == CIVIL) { |
| 399 // Use the civil calendar approximation, which is just arithmetic |
| 400 year = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631
.0 ); |
| 401 month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 ); |
| 402 month = month<11?month:11; |
| 403 startDate = monthStart(year, month); |
| 404 } else { |
| 405 // Guess at the number of elapsed full months since the epoch |
| 406 int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::
SYNODIC_MONTH); |
| 407 |
| 408 startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH); |
| 409 |
| 410 double age = moonAge(internalGetTime(), status); |
| 411 if (U_FAILURE(status)) { |
| 412 status = U_MEMORY_ALLOCATION_ERROR; |
| 413 return; |
| 414 } |
| 415 if ( days - startDate >= 25 && age > 0) { |
| 416 // If we're near the end of the month, assume next month and search
backwards |
| 417 months++; |
| 418 } |
| 419 |
| 420 // Find out the last time that the new moon was actually visible at this
longitude |
| 421 // This returns midnight the night that the moon was visible at sunset. |
| 422 while ((startDate = trueMonthStart(months)) > days) { |
| 423 // If it was after the date in question, back up a month and try aga
in |
| 424 months--; |
| 425 } |
| 426 |
| 427 year = months / 12 + 1; |
| 428 month = months % 12; |
| 429 } |
| 430 |
| 431 dayOfMonth = (days - monthStart(year, month)) + 1; |
| 432 |
| 433 // Now figure out the day of the year. |
| 434 dayOfYear = (days - monthStart(year, 0) + 1); |
| 435 |
| 436 internalSet(UCAL_ERA, 0); |
| 437 internalSet(UCAL_YEAR, year); |
| 438 internalSet(UCAL_EXTENDED_YEAR, year); |
| 439 internalSet(UCAL_MONTH, month); |
| 440 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth); |
| 441 internalSet(UCAL_DAY_OF_YEAR, dayOfYear); |
| 442 } |
| 443 |
| 444 UBool |
| 445 IslamicCalendar::inDaylightTime(UErrorCode& status) const |
| 446 { |
| 447 // copied from GregorianCalendar |
| 448 if (U_FAILURE(status) || (&(getTimeZone()) == NULL && !getTimeZone().useDayl
ightTime())) |
| 449 return FALSE; |
| 450 |
| 451 // Force an update of the state of the Calendar. |
| 452 ((IslamicCalendar*)this)->complete(status); // cast away const |
| 453 |
| 454 return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FAL
SE); |
| 455 } |
| 456 |
| 457 // default century |
| 458 const UDate IslamicCalendar::fgSystemDefaultCentury = DBL_MIN; |
| 459 const int32_t IslamicCalendar::fgSystemDefaultCenturyYear = -1; |
| 460 |
| 461 UDate IslamicCalendar::fgSystemDefaultCenturyStart = DBL_MIN; |
| 462 int32_t IslamicCalendar::fgSystemDefaultCenturyStartYear = -1; |
| 463 |
| 464 |
| 465 UBool IslamicCalendar::haveDefaultCentury() const |
| 466 { |
| 467 return TRUE; |
| 468 } |
| 469 |
| 470 UDate IslamicCalendar::defaultCenturyStart() const |
| 471 { |
| 472 return internalGetDefaultCenturyStart(); |
| 473 } |
| 474 |
| 475 int32_t IslamicCalendar::defaultCenturyStartYear() const |
| 476 { |
| 477 return internalGetDefaultCenturyStartYear(); |
| 478 } |
| 479 |
| 480 UDate |
| 481 IslamicCalendar::internalGetDefaultCenturyStart() const |
| 482 { |
| 483 // lazy-evaluate systemDefaultCenturyStart |
| 484 UBool needsUpdate; |
| 485 UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), ne
edsUpdate); |
| 486 |
| 487 if (needsUpdate) { |
| 488 initializeSystemDefaultCentury(); |
| 489 } |
| 490 |
| 491 // use defaultCenturyStart unless it's the flag value; |
| 492 // then use systemDefaultCenturyStart |
| 493 |
| 494 return fgSystemDefaultCenturyStart; |
| 495 } |
| 496 |
| 497 int32_t |
| 498 IslamicCalendar::internalGetDefaultCenturyStartYear() const |
| 499 { |
| 500 // lazy-evaluate systemDefaultCenturyStartYear |
| 501 UBool needsUpdate; |
| 502 UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), ne
edsUpdate); |
| 503 |
| 504 if (needsUpdate) { |
| 505 initializeSystemDefaultCentury(); |
| 506 } |
| 507 |
| 508 // use defaultCenturyStart unless it's the flag value; |
| 509 // then use systemDefaultCenturyStartYear |
| 510 |
| 511 return fgSystemDefaultCenturyStartYear; |
| 512 } |
| 513 |
| 514 void |
| 515 IslamicCalendar::initializeSystemDefaultCentury() |
| 516 { |
| 517 // initialize systemDefaultCentury and systemDefaultCenturyYear based |
| 518 // on the current time. They'll be set to 80 years before |
| 519 // the current time. |
| 520 UErrorCode status = U_ZERO_ERROR; |
| 521 IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status); |
| 522 if (U_SUCCESS(status)) |
| 523 { |
| 524 calendar.setTime(Calendar::getNow(), status); |
| 525 calendar.add(UCAL_YEAR, -80, status); |
| 526 UDate newStart = calendar.getTime(status); |
| 527 int32_t newYear = calendar.get(UCAL_YEAR, status); |
| 528 umtx_lock(NULL); |
| 529 if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) |
| 530 { |
| 531 fgSystemDefaultCenturyStartYear = newYear; |
| 532 fgSystemDefaultCenturyStart = newStart; |
| 533 } |
| 534 umtx_unlock(NULL); |
| 535 } |
| 536 // We have no recourse upon failure unless we want to propagate the failure |
| 537 // out. |
| 538 } |
| 539 |
| 540 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar) |
| 541 |
| 542 U_NAMESPACE_END |
| 543 |
| 544 #endif |
| 545 |
OLD | NEW |