00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025 #ifndef HAVE_SYS_TIMEB_H
00026 #define HAVE_SYS_TIMEB_H 0
00027 #endif
00028
00029 #if TIME_WITH_SYS_TIME
00030 # include <sys/time.h>
00031 # include <time.h>
00032 #else
00033 #if HAVE_SYS_TIME_H
00034 #include <sys/time.h>
00035 #else
00036 # include <time.h>
00037 # endif
00038 #endif
00039 #if HAVE_SYS_TIMEB_H
00040 #include <sys/timeb.h>
00041 #endif
00042
00043 #ifdef HAVE_SYS_PARAM_H
00044 # include <sys/param.h>
00045 #endif // HAVE_SYS_PARAM_H
00046
00047 #include <math.h>
00048 #include <string.h>
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 #include <locale.h>
00052 #include <ctype.h>
00053
00054 #include "date_object.h"
00055 #include "error_object.h"
00056 #include "operations.h"
00057
00058 #include "date_object.lut.h"
00059
00060 using namespace KJS;
00061
00062
00063
00064 const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0};
00065
00066 DateInstanceImp::DateInstanceImp(const Object &proto)
00067 : ObjectImp(proto)
00068 {
00069 }
00070
00071
00072
00073 const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0};
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 DatePrototypeImp::DatePrototypeImp(ExecState *,
00128 ObjectPrototypeImp *objectProto)
00129 : DateInstanceImp(Object(objectProto))
00130 {
00131 Value protect(this);
00132 setInternalValue(Number(NaN));
00133
00134 }
00135
00136 Value DatePrototypeImp::get(ExecState *exec, const UString &propertyName) const
00137 {
00138 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this );
00139 }
00140
00141
00142
00143 DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len)
00144 : InternalFunctionImp(
00145 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
00146 ), id(abs(i)), utc(i<0)
00147
00148 {
00149 Value protect(this);
00150 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
00151 }
00152
00153 bool DateProtoFuncImp::implementsCall() const
00154 {
00155 return true;
00156 }
00157
00158 Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00159 {
00160 if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) &&
00161 !thisObj.inherits(&DateInstanceImp::info)) {
00162
00163
00164
00165
00166 Object err = Error::create(exec,TypeError);
00167 exec->setException(err);
00168 return err;
00169 }
00170
00171
00172 Value result;
00173 UString s;
00174 const int bufsize=100;
00175 char timebuffer[bufsize];
00176 CString oldlocale = setlocale(LC_TIME,NULL);
00177 if (!oldlocale.c_str())
00178 oldlocale = setlocale(LC_ALL, NULL);
00179 Value v = thisObj.internalValue();
00180 double milli = v.toNumber(exec);
00181 time_t tv = (time_t) floor(milli / 1000.0);
00182 int ms = int(milli - tv * 1000.0);
00183
00184
00185
00186
00187
00188 if (sizeof(time_t) == 4)
00189 {
00190
00191 if ( (time_t)-1 < 0 ) {
00192 if ( floor(milli / 1000.0) > ((double)((uint)1<<31)-1) ) {
00193 #ifdef KJS_VERBOSE
00194 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(milli/(1000.0*365.25*86400)+1970));
00195 #endif
00196 tv = ((uint)1<<31)-1;
00197 ms = 0;
00198 }
00199 }
00200 else
00201
00202 if ( floor(milli / 1000.0) > ((double)(uint)-1) ) {
00203 #ifdef KJS_VERBOSE
00204 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(milli/(1000.0*365.25*86400)+1970));
00205 #endif
00206 tv = (uint)-1;
00207 ms = 0;
00208 }
00209 }
00210
00211 struct tm *t;
00212 if (utc)
00213 t = gmtime(&tv);
00214 else
00215 t = localtime(&tv);
00216
00217 switch (id) {
00218 case ToString:
00219 case ToDateString:
00220 case ToTimeString:
00221 case ToGMTString:
00222 case ToUTCString:
00223 setlocale(LC_TIME,"C");
00224 if (id == DateProtoFuncImp::ToDateString) {
00225 strftime(timebuffer, bufsize, "%x",t);
00226 } else if (id == DateProtoFuncImp::ToTimeString) {
00227 strftime(timebuffer, bufsize, "%X",t);
00228 } else {
00229 t = (id == ToString ? localtime(&tv) : gmtime(&tv));
00230 strftime(timebuffer, bufsize, "%a, %d %b %Y %H:%M:%S %z", t);
00231 }
00232 setlocale(LC_TIME,oldlocale.c_str());
00233 result = String(timebuffer);
00234 break;
00235 case ToLocaleString:
00236 strftime(timebuffer, bufsize, "%c", t);
00237 result = String(timebuffer);
00238 break;
00239 case ToLocaleDateString:
00240 strftime(timebuffer, bufsize, "%x", t);
00241 result = String(timebuffer);
00242 break;
00243 case ToLocaleTimeString:
00244 strftime(timebuffer, bufsize, "%X", t);
00245 result = String(timebuffer);
00246 break;
00247 case ValueOf:
00248 result = Number(milli);
00249 break;
00250 case GetTime:
00251 result = Number(milli);
00252 break;
00253 case GetYear:
00254
00255
00256 if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat )
00257 result = Number(t->tm_year);
00258 else
00259 result = Number(1900 + t->tm_year);
00260 break;
00261 case GetFullYear:
00262 result = Number(1900 + t->tm_year);
00263 break;
00264 case GetMonth:
00265 result = Number(t->tm_mon);
00266 break;
00267 case GetDate:
00268 result = Number(t->tm_mday);
00269 break;
00270 case GetDay:
00271 result = Number(t->tm_wday);
00272 break;
00273 case GetHours:
00274 result = Number(t->tm_hour);
00275 break;
00276 case GetMinutes:
00277 result = Number(t->tm_min);
00278 break;
00279 case GetSeconds:
00280 result = Number(t->tm_sec);
00281 break;
00282 case GetMilliSeconds:
00283 result = Number(ms);
00284 break;
00285 case GetTimezoneOffset:
00286 #if defined BSD || defined(__APPLE__)
00287 result = Number(-(t->tm_gmtoff / 60) + (t->tm_isdst > 0 ? 60 : 0));
00288 #else
00289 # if defined(__BORLANDC__)
00290 #error please add daylight savings offset here!
00291 result = Number(_timezone / 60 - (t->tm_isdst > 0 ? 60 : 0));
00292 # else
00293 result = Number((timezone / 60 - (t->tm_isdst > 0 ? 60 : 0 )));
00294 # endif
00295 #endif
00296 break;
00297 case SetTime:
00298 milli = roundValue(exec,args[0]);
00299 result = Number(milli);
00300 thisObj.setInternalValue(result);
00301 break;
00302 case SetMilliSeconds:
00303 ms = args[0].toInt32(exec);
00304 break;
00305 case SetSeconds:
00306 t->tm_sec = args[0].toInt32(exec);
00307 break;
00308 case SetMinutes:
00309 t->tm_min = args[0].toInt32(exec);
00310 break;
00311 case SetHours:
00312 t->tm_hour = args[0].toInt32(exec);
00313 break;
00314 case SetDate:
00315 t->tm_mday = args[0].toInt32(exec);
00316 break;
00317 case SetMonth:
00318 t->tm_mon = args[0].toInt32(exec);
00319 break;
00320 case SetFullYear:
00321 t->tm_year = args[0].toInt32(exec) - 1900;
00322 break;
00323 case SetYear:
00324 t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec);
00325 break;
00326 }
00327
00328 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
00329 id == SetMinutes || id == SetHours || id == SetDate ||
00330 id == SetMonth || id == SetFullYear ) {
00331 result = Number(mktime(t) * 1000.0 + ms);
00332 thisObj.setInternalValue(result);
00333 }
00334
00335 return result;
00336 }
00337
00338
00339
00340
00341
00342 DateObjectImp::DateObjectImp(ExecState *exec,
00343 FunctionPrototypeImp *funcProto,
00344 DatePrototypeImp *dateProto)
00345 : InternalFunctionImp(funcProto)
00346 {
00347 Value protect(this);
00348
00349 put(exec,"prototype", Object(dateProto), DontEnum|DontDelete|ReadOnly);
00350
00351 put(exec,"parse", Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1)), DontEnum);
00352 put(exec,"UTC", Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7)), DontEnum);
00353
00354
00355 put(exec,"length", Number(7), ReadOnly|DontDelete|DontEnum);
00356 }
00357
00358 bool DateObjectImp::implementsConstruct() const
00359 {
00360 return true;
00361 }
00362
00363
00364 Object DateObjectImp::construct(ExecState *exec, const List &args)
00365 {
00366 int numArgs = args.size();
00367
00368 #ifdef KJS_VERBOSE
00369 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
00370 #endif
00371 Value value;
00372
00373 if (numArgs == 0) {
00374 #if HAVE_SYS_TIMEB_H
00375 # if defined(__BORLANDC__)
00376 struct timeb timebuffer;
00377 ftime(&timebuffer);
00378 # else
00379 struct _timeb timebuffer;
00380 _ftime(&timebuffer);
00381 # endif
00382 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
00383 #else
00384 struct timeval tv;
00385 gettimeofday(&tv, 0L);
00386 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
00387 #endif
00388 value = Number(utc);
00389 } else if (numArgs == 1) {
00390 UString s = args[0].toString(exec);
00391 double d = s.toDouble();
00392 if (isNaN(d))
00393 value = parseDate(s);
00394 else
00395 value = Number(d);
00396 } else {
00397 struct tm t;
00398 memset(&t, 0, sizeof(t));
00399 int year = args[0].toInt32(exec);
00400
00401 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00402 t.tm_mon = args[1].toInt32(exec);
00403 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
00404 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
00405 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
00406 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
00407 t.tm_isdst = -1;
00408 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
00409 value = Number(mktime(&t) * 1000.0 + ms);
00410 }
00411
00412 Object proto = exec->interpreter()->builtinDatePrototype();
00413 Object ret(new DateInstanceImp(proto));
00414 ret.setInternalValue(timeClip(value));
00415 return ret;
00416 }
00417
00418 bool DateObjectImp::implementsCall() const
00419 {
00420 return true;
00421 }
00422
00423
00424 Value DateObjectImp::call(ExecState *, Object &, const List &)
00425 {
00426 #ifdef KJS_VERBOSE
00427 fprintf(stderr,"DateObjectImp::call - current time\n");
00428 #endif
00429 time_t t = time(0L);
00430 UString s(ctime(&t));
00431
00432
00433 return String(s.substr(0, s.size() - 1));
00434 }
00435
00436
00437
00438 DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
00439 int i, int len)
00440 : InternalFunctionImp(funcProto), id(i)
00441 {
00442 Value protect(this);
00443 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
00444 }
00445
00446 bool DateObjectFuncImp::implementsCall() const
00447 {
00448 return true;
00449 }
00450
00451
00452 Value DateObjectFuncImp::call(ExecState *exec, Object &, const List &args)
00453 {
00454 if (id == Parse) {
00455 return parseDate(args[0].toString(exec));
00456 } else {
00457 struct tm t;
00458 memset(&t, 0, sizeof(t));
00459 int n = args.size();
00460 int year = args[0].toInt32(exec);
00461
00462 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
00463 t.tm_mon = args[1].toInt32(exec);
00464 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
00465 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
00466 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
00467 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
00468 int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
00469 return Number(mktime(&t) * 1000.0 + ms);
00470 }
00471 }
00472
00473
00474
00475
00476 Value KJS::parseDate(const UString &u)
00477 {
00478 #ifdef KJS_VERBOSE
00479 fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
00480 #endif
00481 double seconds = KRFCDate_parseDate( u );
00482 #ifdef KJS_VERBOSE
00483 fprintf(stderr,"KRFCDate_parseDate returned seconds=%g\n",seconds);
00484 bool withinLimits = true;
00485 if ( sizeof(time_t) == 4 )
00486 {
00487 int limit = ((time_t)-1 < 0) ? 2038 : 2115;
00488 if ( seconds > (limit-1970) * 365.25 * 86400 ) {
00489 fprintf(stderr, "date above time_t limit. Year seems to be %d\n", (int)(seconds/(365.25*86400)+1970));
00490 withinLimits = false;
00491 }
00492 }
00493 if ( withinLimits ) {
00494 time_t lsec = (time_t)seconds;
00495 fprintf(stderr, "this is: %s\n", ctime(&lsec));
00496 }
00497 #endif
00498
00499 return Number(seconds == -1 ? NaN : seconds * 1000.0);
00500 }
00501
00503
00504 static double ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00505 {
00506
00507
00508 double ret = (day - 32075)
00509 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00510 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00511 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00512 - 2440588;
00513 ret = 24*ret + hour;
00514 ret = 60*ret + minute;
00515 ret = 60*ret + second;
00516
00517 return ret;
00518 }
00519
00520 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
00521
00522
00523
00524 static const struct {
00525 const char *tzName;
00526 int tzOffset;
00527 } known_zones[] = {
00528 { "UT", 0 },
00529 { "GMT", 0 },
00530 { "EST", -300 },
00531 { "EDT", -240 },
00532 { "CST", -360 },
00533 { "CDT", -300 },
00534 { "MST", -420 },
00535 { "MDT", -360 },
00536 { "PST", -480 },
00537 { "PDT", -420 },
00538 { 0, 0 }
00539 };
00540
00541 int KJS::local_timeoffset()
00542 {
00543 static int local_offset = -1;
00544
00545 if ( local_offset != -1 ) return local_offset;
00546
00547 time_t local = time(0);
00548 struct tm* tm_local = gmtime(&local);
00549 local_offset = local-mktime(tm_local);
00550 if(tm_local->tm_isdst)
00551 local_offset += 3600;
00552
00553 return local_offset;
00554 }
00555
00556 double KJS::KRFCDate_parseDate(const UString &_date)
00557 {
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 double result = -1;
00572 int offset = 0;
00573 bool have_tz = false;
00574 char *newPosStr;
00575 const char *dateString = _date.ascii();
00576 int day = 0;
00577 char monthStr[4];
00578 int month = -1;
00579 int year = 0;
00580 int hour = 0;
00581 int minute = 0;
00582 int second = 0;
00583 bool have_time = false;
00584
00585
00586 while(*dateString && isspace(*dateString))
00587 dateString++;
00588
00589 const char *wordStart = dateString;
00590
00591 while(*dateString && !isdigit(*dateString))
00592 {
00593 if ( isspace(*dateString) && dateString - wordStart >= 3 )
00594 {
00595 monthStr[0] = tolower(*wordStart++);
00596 monthStr[1] = tolower(*wordStart++);
00597 monthStr[2] = tolower(*wordStart++);
00598 monthStr[3] = '\0';
00599
00600 const char *str = strstr(haystack, monthStr);
00601 if (str)
00602 month = (str-haystack)/3;
00603 while(*dateString && isspace(*dateString))
00604 dateString++;
00605 wordStart = dateString;
00606 }
00607 else
00608 dateString++;
00609 }
00610
00611 while(*dateString && isspace(*dateString))
00612 dateString++;
00613
00614 if (!*dateString)
00615 return result;
00616
00617
00618 day = strtol(dateString, &newPosStr, 10);
00619 dateString = newPosStr;
00620
00621 if ((day < 1) || (day > 31))
00622 return result;
00623 if (!*dateString)
00624 return result;
00625
00626 if (*dateString == '/' && day <= 12 && month == -1)
00627 {
00628 dateString++;
00629
00630 month = day - 1;
00631 day = strtol(dateString, &newPosStr, 10);
00632 dateString = newPosStr;
00633 if (*dateString == '/')
00634 dateString++;
00635 if (!*dateString)
00636 return result;
00637
00638 }
00639 else
00640 {
00641 if (*dateString == '-')
00642 dateString++;
00643
00644 while(*dateString && isspace(*dateString))
00645 dateString++;
00646
00647 if (*dateString == ',')
00648 dateString++;
00649
00650 if ( month == -1 )
00651 {
00652 for(int i=0; i < 3;i++)
00653 {
00654 if (!*dateString || (*dateString == '-') || isspace(*dateString))
00655 return result;
00656 monthStr[i] = tolower(*dateString++);
00657 }
00658 monthStr[3] = '\0';
00659
00660 newPosStr = (char*)strstr(haystack, monthStr);
00661
00662 if (!newPosStr)
00663 return result;
00664
00665 month = (newPosStr-haystack)/3;
00666
00667 if ((month < 0) || (month > 11))
00668 return result;
00669
00670 while(*dateString && (*dateString != '-') && !isspace(*dateString))
00671 dateString++;
00672
00673 if (!*dateString)
00674 return result;
00675
00676
00677 if ((*dateString != '-') && (*dateString != '/') && !isspace(*dateString))
00678 return result;
00679 dateString++;
00680 }
00681
00682 if ((month < 0) || (month > 11))
00683 return result;
00684 }
00685
00686
00687 year = strtol(dateString, &newPosStr, 10);
00688 dateString = newPosStr;
00689
00690
00691 if ((year >= 0) && (year < 50))
00692 year += 2000;
00693
00694 if ((year >= 50) && (year < 100))
00695 year += 1900;
00696
00697 if ((year < 1900) || (year > 2500))
00698 return result;
00699
00700
00701 if (*dateString)
00702 {
00703
00704 if (!isspace(*dateString++))
00705 return false;
00706
00707 have_time = true;
00708 hour = strtol(dateString, &newPosStr, 10);
00709 dateString = newPosStr;
00710
00711 if ((hour < 0) || (hour > 23))
00712 return result;
00713
00714 if (!*dateString)
00715 return result;
00716
00717
00718 if (*dateString++ != ':')
00719 return result;
00720
00721 minute = strtol(dateString, &newPosStr, 10);
00722 dateString = newPosStr;
00723
00724 if ((minute < 0) || (minute > 59))
00725 return result;
00726
00727
00728 if (*dateString && *dateString != ':' && !isspace(*dateString))
00729 return result;
00730
00731
00732 if (*dateString ==':') {
00733 dateString++;
00734
00735 second = strtol(dateString, &newPosStr, 10);
00736 dateString = newPosStr;
00737
00738 if ((second < 0) || (second > 59))
00739 return result;
00740 }
00741
00742 while(*dateString && isspace(*dateString))
00743 dateString++;
00744 }
00745
00746
00747
00748 if (*dateString) {
00749
00750 if ( (dateString[0] == 'G' && dateString[1] == 'M' && dateString[2] == 'T')
00751 || (dateString[0] == 'U' && dateString[1] == 'T' && dateString[2] == 'C') )
00752 {
00753 dateString += 3;
00754 have_tz = true;
00755 }
00756
00757 while (*dateString && isspace(*dateString))
00758 ++dateString;
00759
00760 if ((*dateString == '+') || (*dateString == '-')) {
00761 offset = strtol(dateString, &newPosStr, 10);
00762 dateString = newPosStr;
00763
00764 if ((offset < -9959) || (offset > 9959))
00765 return result;
00766
00767 int sgn = (offset < 0)? -1:1;
00768 offset = abs(offset);
00769 if ( *dateString == ':' ) {
00770 int offset2 = strtol(dateString, &newPosStr, 10);
00771 dateString = newPosStr;
00772 offset = (offset*60 + offset2)*sgn;
00773 }
00774 else
00775 offset = ((offset / 100)*60 + (offset % 100))*sgn;
00776 have_tz = true;
00777 } else {
00778 for (int i=0; known_zones[i].tzName != 0; i++) {
00779 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
00780 offset = known_zones[i].tzOffset;
00781 have_tz = true;
00782 break;
00783 }
00784 }
00785 }
00786 }
00787
00788 #if 0
00789 if (sizeof(time_t) == 4)
00790 {
00791 if ((time_t)-1 < 0)
00792 {
00793 if (year >= 2038)
00794 {
00795 year = 2038;
00796 month = 0;
00797 day = 1;
00798 hour = 0;
00799 minute = 0;
00800 second = 0;
00801 }
00802 }
00803 else
00804 {
00805 if (year >= 2115)
00806 {
00807 year = 2115;
00808 month = 0;
00809 day = 1;
00810 hour = 0;
00811 minute = 0;
00812 second = 0;
00813 }
00814 }
00815 }
00816 #endif
00817
00818 if (!have_time && !have_tz) {
00819
00820 struct tm t;
00821 memset(&t, 0, sizeof(tm));
00822 t.tm_mday = day;
00823 t.tm_mon = month;
00824 t.tm_year = year - 1900;
00825 t.tm_isdst = -1;
00826 return mktime(&t);
00827 }
00828
00829 if(!have_tz)
00830 offset = local_timeoffset();
00831 else
00832 offset *= 60;
00833
00834 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
00835
00836
00837 if ((offset > 0) && (offset > result))
00838 offset = 0;
00839
00840 result -= offset;
00841
00842
00843
00844
00845 if (result < 1) result = 1;
00846
00847 return result;
00848 }
00849
00850
00851 Value KJS::timeClip(const Value &t)
00852 {
00853
00854 return t;
00855 }
00856