00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00015
00016
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018
00020
00021 ON_TextLog::ON_TextLog() : m_pFile(0), m_pString(0), m_indent(""), m_beginning_of_line(1), m_indent_size(0)
00022 {
00023 SetFloatFormat("%g");
00024 SetDoubleFormat("%.17g");
00025 }
00026
00027 ON_TextLog::ON_TextLog( FILE* pFile ) : m_pFile(pFile), m_pString(0), m_indent(""), m_beginning_of_line(1), m_indent_size(0)
00028 {
00029 SetFloatFormat("%g");
00030 SetDoubleFormat("%.17g");
00031 }
00032
00033 ON_TextLog::ON_TextLog( ON_wString& wstr ) : m_pFile(0), m_pString(&wstr), m_indent(""), m_beginning_of_line(1), m_indent_size(0)
00034 {
00035 SetFloatFormat("%g");
00036 SetDoubleFormat("%.17g");
00037 }
00038
00039 ON_TextLog::~ON_TextLog()
00040 {
00041 }
00042
00043 void ON_TextLog::SetDoubleFormat(const char* sFormat)
00044 {
00045 m_double_format = sFormat;
00046 m_double2_format = m_double_format + ", " + m_double_format;
00047 m_double3_format = m_double2_format + ", " + m_double_format;
00048 m_double4_format = m_double3_format + ", " + m_double_format;
00049 }
00050
00051 void ON_TextLog::GetDoubleFormat( ON_String& s ) const
00052 {
00053 s = m_double_format;
00054 }
00055
00056 void ON_TextLog::SetFloatFormat(const char* sFormat)
00057 {
00058 m_float_format = sFormat;
00059 m_float2_format = m_float_format + ", " + m_float_format;
00060 m_float3_format = m_float2_format + ", " + m_float_format;
00061 m_float4_format = m_float3_format + ", " + m_float_format;
00062 }
00063
00064 void ON_TextLog::GetFloatFormat( ON_String& s ) const
00065 {
00066 s = m_float_format;
00067 }
00068
00069 void ON_TextLog::PushIndent()
00070 {
00071 if ( m_indent_size > 0 ) {
00072 int i;
00073 for ( i = 0; i < m_indent_size; i++ ) {
00074 m_indent += ' ';
00075 }
00076 }
00077 else {
00078 m_indent += "\t";
00079 }
00080 }
00081
00082 void ON_TextLog::PopIndent()
00083 {
00084 const int length = m_indent.Length();
00085 const int indent_lenth = m_indent_size>0 ? m_indent_size : 1;
00086 if ( length >= indent_lenth ) {
00087 m_indent.SetLength(length-indent_lenth);
00088 }
00089 else {
00090 m_indent.Destroy();
00091 }
00092 }
00093
00094 int ON_TextLog::IndentSize() const
00095 {
00096
00097
00098 return m_indent_size;
00099 }
00100
00101 void ON_TextLog::SetIndentSize(int s)
00102 {
00103 m_indent_size = (s>0) ? s : 0;
00104 }
00105
00106 void ON_TextLog::Print( const char* format, ... )
00107 {
00108
00109 const int MAX_MSG_LENGTH = 2047;
00110 char s[MAX_MSG_LENGTH+1];
00111 va_list args;
00112
00113 s[0] = 0;
00114 if (format)
00115 {
00116 va_start(args, format);
00117 on_vsnprintf( s, MAX_MSG_LENGTH-1, format, args);
00118 va_end(args);
00119 s[MAX_MSG_LENGTH] = 0;
00120 }
00121 if ( *s )
00122 {
00123 char* s0 = s;
00124 char* s1 = s;
00125 for ( s1 = s0; *s1; s1++) {
00126 if ( *s1 == '\n' ) {
00127 *s1 = 0;
00128 if ( m_beginning_of_line && m_indent && m_indent[0] )
00129 AppendText( m_indent );
00130 if (*s0)
00131 AppendText(s0);
00132 AppendText("\n");
00133 m_beginning_of_line = 1;
00134 s0 = s1+1;
00135 }
00136 }
00137 if (*s0) {
00138 if ( m_beginning_of_line && m_indent && m_indent[0] )
00139 AppendText( m_indent );
00140 AppendText(s0);
00141 m_beginning_of_line = 0;
00142 }
00143 }
00144 }
00145
00146 void ON_TextLog::Print( const wchar_t* wformat, ... )
00147 {
00148
00149 const int MAX_MSG_LENGTH = 2047;
00150 wchar_t s[MAX_MSG_LENGTH+1];
00151 va_list args;
00152
00153 s[0] = 0;
00154 if (wformat)
00155 {
00156 va_start(args, wformat);
00157 on_vsnwprintf( s, MAX_MSG_LENGTH-1, wformat, args);
00158 va_end(args);
00159 s[MAX_MSG_LENGTH] = 0;
00160 }
00161 if ( *s )
00162 {
00163 wchar_t* s0 = s;
00164 wchar_t* s1 = s;
00165 for ( s1 = s0; *s1; s1++) {
00166 if ( *s1 == '\n' ) {
00167 *s1 = 0;
00168 if ( m_beginning_of_line && m_indent && m_indent[0] )
00169 AppendText( m_indent );
00170 if (*s0)
00171 AppendText(s0);
00172 AppendText("\n");
00173 m_beginning_of_line = 1;
00174 s0 = s1+1;
00175 }
00176 }
00177 if (*s0) {
00178 if ( m_beginning_of_line && m_indent && m_indent[0] )
00179 AppendText( m_indent );
00180 AppendText(s0);
00181 m_beginning_of_line = 0;
00182 }
00183 }
00184 }
00185
00186
00187 void ON_TextLog::AppendText( const char* s )
00188 {
00189
00190 if ( s && *s )
00191 {
00192 if ( m_pString )
00193 {
00194 (*m_pString) += s;
00195 }
00196 else if ( m_pFile )
00197 {
00198 fputs( s, m_pFile );
00199 }
00200 else
00201 {
00202 printf("%s",s);
00203 }
00204 }
00205 }
00206
00207 void ON_TextLog::AppendText( const wchar_t* s )
00208 {
00209
00210 if ( m_pString )
00211 {
00212 (*m_pString) += s;
00213 }
00214 else
00215 {
00216
00217
00218
00219
00220 ON_String str = s;
00221 AppendText(str.Array());
00222 }
00223 }
00224
00225 void ON_TextLog::Print( float x )
00226 {
00227 if ( ON_UNSET_FLOAT == x )
00228 Print("ON_UNSET_FLOAT");
00229 else
00230 Print(m_float_format,x);
00231 }
00232
00233 void ON_TextLog::Print( double x )
00234 {
00235 if ( ON_UNSET_VALUE == x )
00236 Print("ON_UNSET_VALUE");
00237 else
00238 Print(m_double_format,x);
00239 }
00240
00241 void ON_TextLog::Print( const ON_2dPoint& p )
00242 {
00243 Print("(");
00244 Print(m_double2_format, p.x, p.y);
00245 Print(")");
00246 }
00247
00248 void ON_TextLog::Print( const ON_3dPoint& p )
00249 {
00250 Print("(");
00251 if ( ON_3dPoint::UnsetPoint == p )
00252 Print("UnsetPoint");
00253 else
00254 Print(m_double3_format, p.x, p.y, p.z );
00255 Print(")");
00256 }
00257
00258 void ON_TextLog::Print( const ON_4dPoint& p )
00259 {
00260 Print("[");
00261 Print(m_double4_format, p.x, p.y, p.z, p.w );
00262 Print("]");
00263 }
00264
00265 void ON_TextLog::Print( const ON_2dVector& p )
00266 {
00267 Print("<");
00268 Print(m_double2_format, p.x, p.y);
00269 Print(">");
00270 }
00271
00272 void ON_TextLog::Print( const ON_3dVector& p )
00273 {
00274 Print("<");
00275 if ( ON_3dVector::UnsetVector == p )
00276 Print("UnsetVector");
00277 else
00278 Print(m_double3_format, p.x, p.y, p.z);
00279 Print(">");
00280 }
00281
00282 void ON_TextLog::Print( const ON_Xform& xform )
00283 {
00284 if ( xform.IsIdentity() )
00285 {
00286 Print("identity transformation\n");
00287 }
00288 else if ( xform.IsZero() )
00289 {
00290 Print("zero transformation\n");
00291 }
00292 else
00293 {
00294 Print(m_double4_format,xform[0][0],xform[0][1],xform[0][2],xform[0][3]);
00295 Print("\n");
00296 Print(m_double4_format,xform[1][0],xform[1][1],xform[1][2],xform[1][3]);
00297 Print("\n");
00298 Print(m_double4_format,xform[2][0],xform[2][1],xform[2][2],xform[2][3]);
00299 Print("\n");
00300 Print(m_double4_format,xform[3][0],xform[3][1],xform[3][2],xform[3][3]);
00301 Print("\n");
00302 }
00303 }
00304
00305 void ON_TextLog::Print( const ON_UUID& uuid )
00306 {
00307 Print("%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
00308 uuid.Data1, uuid.Data2, uuid.Data3,
00309 uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3],
00310 uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]
00311 );
00312 }
00313
00314 void ON_TextLog::Print( const ON_COMPONENT_INDEX& ci )
00315 {
00316 switch( ci.m_type )
00317 {
00318 case ON_COMPONENT_INDEX::invalid_type:
00319 Print("invalid_type(%d)",ci.m_index);
00320 break;
00321 case ON_COMPONENT_INDEX::brep_vertex:
00322 Print("brep_vertex(%d)",ci.m_index);
00323 break;
00324 case ON_COMPONENT_INDEX::brep_edge:
00325 Print("brep_edge(%d)",ci.m_index);
00326 break;
00327 case ON_COMPONENT_INDEX::brep_face:
00328 Print("brep_face(%d)",ci.m_index);
00329 break;
00330 case ON_COMPONENT_INDEX::brep_trim:
00331 Print("brep_trim(%d)",ci.m_index);
00332 break;
00333 case ON_COMPONENT_INDEX::brep_loop:
00334 Print("brep_loop(%d)",ci.m_index);
00335 break;
00336 case ON_COMPONENT_INDEX::mesh_vertex:
00337 Print("mesh_vertex(%d)",ci.m_index);
00338 break;
00339 case ON_COMPONENT_INDEX::meshtop_vertex:
00340 Print("meshtop_vertex(%d)",ci.m_index);
00341 break;
00342 case ON_COMPONENT_INDEX::meshtop_edge:
00343 Print("meshtop_edge(%d)",ci.m_index);
00344 break;
00345 case ON_COMPONENT_INDEX::mesh_face:
00346 Print("mesh_face(%d)",ci.m_index);
00347 break;
00348 case ON_COMPONENT_INDEX::idef_part:
00349 Print("idef_part(%d)",ci.m_index);
00350 break;
00351 case ON_COMPONENT_INDEX::polycurve_segment:
00352 Print("polycurve_segment(%d)",ci.m_index);
00353 break;
00354 case ON_COMPONENT_INDEX::pointcloud_point:
00355 Print("pointcloud_point(%d)",ci.m_index);
00356 break;
00357 case ON_COMPONENT_INDEX::group_member:
00358 Print("group_member(%d)",ci.m_index);
00359 break;
00360 case ON_COMPONENT_INDEX::no_type:
00361 Print("no_type(%d)",ci.m_index);
00362 break;
00363 default:
00364 Print("ON_COMPONENT_INDEX(%d,%d)",ci.m_type,ci.m_index);
00365 break;
00366 }
00367 }
00368
00369 void ON_TextLog::Print( const ON_wString& string )
00370 {
00371 const wchar_t* s = string;
00372 if ( s && *s )
00373 AppendText(s);
00374 }
00375
00376 void ON_TextLog::Print( const ON_String& string )
00377 {
00378 const char* s = string;
00379 if ( s && *s )
00380 AppendText(s);
00381 }
00382
00383 void ON_TextLog::PrintString( const char* s )
00384 {
00385 if ( s && *s )
00386 AppendText(s);
00387 }
00388
00389 void ON_TextLog::PrintNewLine()
00390 {
00391 Print("\n");
00392 }
00393
00394
00395 void ON_TextLog::PrintString( const wchar_t* s )
00396 {
00397 if ( s && *s )
00398 AppendText(s);
00399 }
00400
00401 void ON_TextLog::PrintRGB( const ON_Color& color )
00402 {
00403 if ( color == ON_UNSET_COLOR )
00404 Print("ON_UNSET_COLOR");
00405 else
00406 Print("%d %d %d",color.Red(),color.Green(),color.Blue());
00407 }
00408
00409 void ON_TextLog::PrintTime( const struct tm& t )
00410 {
00411 if ( 0 != t.tm_sec
00412 || 0 != t.tm_min
00413 || 0 != t.tm_hour
00414 || 0 != t.tm_mday
00415 || 0 != t.tm_mon
00416 || 0 != t.tm_year
00417 || 0 != t.tm_wday
00418 )
00419 {
00420 const char* sDayName[8] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","<invalid day>"};
00421 const char* sMonName[13] = {"January","February","March","April","May","June",
00422 "July","August","September","October","November","December","<invalid month>"};
00423 int wday = t.tm_wday;
00424 if ( wday < 0 || wday > 6 )
00425 wday = 7;
00426 int mon = t.tm_mon;
00427 if ( mon < 0 || mon > 11 )
00428 mon = 12;
00429
00430 Print("%s %s %02d %02d:%02d:%02d %4d",
00431 sDayName[wday],
00432 sMonName[mon],
00433 t.tm_mday,
00434 t.tm_hour,
00435 t.tm_min,
00436 t.tm_sec,
00437 t.tm_year+1900);
00438 }
00439 }
00440
00441
00442 void ON_TextLog::PrintPointList( int dim, int is_rat, int count, int stride, const double* P,
00443 const char* sPreamble )
00444 {
00445 double w, x;
00446 int i, j, cvdim;
00447
00448 ON_String preamble = "";
00449 if ( sPreamble && *sPreamble )
00450 preamble += sPreamble;
00451 cvdim = (is_rat) ? dim+1 : dim;
00452
00453 if ( count == 0 ) {
00454 Print( "%sEMPTY point list\n", preamble.Array() );
00455 }
00456 else if ( !P ) {
00457 Print( "%sNULL point list\n", preamble.Array() );
00458 }
00459
00460 for ( i = 0; i < count; i++ ) {
00461 Print( "%s[%2d] %c", preamble.Array(), i, (is_rat) ? '[' : '(' );
00462 Print( m_double_format, P[0] );
00463 for ( j = 1; j < cvdim; j++ ) {
00464 Print( ", ");
00465 Print(m_double_format, P[j] );
00466 }
00467 Print("%c", (is_rat) ? ']' : ')' );
00468 if ( is_rat )
00469 {
00470 w = P[dim];
00471 if ( w != 0.0 )
00472 {
00473
00474 w = 1.0/w;
00475 x = w*P[0];
00476 Print( " = (");
00477 Print( m_double_format, x );
00478 for ( j = 1; j < dim; j++ )
00479 {
00480 x = w*P[j];
00481 Print( ", ");
00482 Print( m_double_format, x );
00483 }
00484 Print(")");
00485 }
00486 }
00487 Print("\n");
00488 P += stride;
00489 }
00490 }
00491
00492 void ON_TextLog::PrintPointGrid( int dim, int is_rat,
00493 int point_count0, int point_count1,
00494 int point_stride0, int point_stride1,
00495 const double* P,
00496 const char* sPreamble )
00497 {
00498 char s[1024];
00499 int i;
00500 if (!sPreamble || !sPreamble[0])
00501 sPreamble = "point";
00502 for ( i = 0; i < point_count0; i++ ) {
00503 sprintf( s, "%s[%2d]", sPreamble, i );
00504 PrintPointList( dim, is_rat, point_count1, point_stride1, P + i*point_stride0, s );
00505 }
00506 }
00507
00508 void ON_TextLog::PrintKnotVector( int order, int cv_count, const double* knot )
00509 {
00510 int i, i0, mult, knot_count;
00511 if ( !knot )
00512 Print("NULL knot vector\n");
00513 if ( order < 2 )
00514 Print("knot vector order < 2\n");
00515 if ( cv_count < order )
00516 Print("knot vector cv_count < order\n");
00517 if ( order >= 2 && cv_count >= order && knot ) {
00518 knot_count = ON_KnotCount( order, cv_count );
00519 i = i0 = 0;
00520 Print("index value mult delta\n");
00521 while ( i < knot_count ) {
00522 mult = 1;
00523 while ( i+mult < knot_count && knot[i] == knot[i+mult] )
00524 mult++;
00525 if ( i == 0 ) {
00526 Print( "%5d %23.17g %4d\n", i, knot[i], mult );
00527 }
00528 else {
00529 Print( "%5d %23.17g %4d %10.4g\n", i, knot[i], mult, knot[i]-knot[i0] );
00530 }
00531 i0 = i;
00532 i += mult;
00533 }
00534 }
00535 }
00536
00537 void ON_TextLog::Print( const ON_3dPointArray& a, const char* sPreamble )
00538 {
00539 const double* p = (a.Array() ? &a.Array()[0].x : NULL );
00540 PrintPointList( 3, false, a.Count(), 3, p, sPreamble );
00541 }
00542
00543 void ON_TextLog::Print( const ON_Matrix& M, const char* sPreamble, int precision )
00544 {
00545 double x;
00546 char digit[10] = {'0','1','2','3','4','5','6','7','8','9'};
00547 char* sRow;
00548 char* sIJ;
00549 int xi, row_count, column_count, row_index, column_index;
00550
00551 row_count = M.RowCount();
00552 column_count = M.ColCount();
00553
00554 sRow = (char*)alloca( (5*column_count + 2 + 64)*sizeof(*sRow) );
00555
00556 if ( !sPreamble )
00557 sPreamble = "Matrix";
00558
00559 Print("%s (%d rows %d columns)\n",sPreamble,row_count,column_count);
00560 for ( row_index = 0; row_index < row_count; row_index++ ) {
00561 sIJ = sRow;
00562 Print("%5d:",row_index);
00563 if ( precision > 3 ) {
00564 for ( column_index = 0; column_index < column_count; column_index++ ) {
00565 x = M.m[row_index][column_index];
00566 Print( " %8f",x);
00567 }
00568 Print("\n");
00569 }
00570 else {
00571 for ( column_index = 0; column_index < column_count; column_index++ ) {
00572 x = M.m[row_index][column_index];
00573 if ( x == 0.0 ) {
00574 strcpy( sIJ, " 0 " );
00575 sIJ += 4;
00576 }
00577 else {
00578 *sIJ++ = ' ';
00579 *sIJ++ = ( x >0.0 ) ? '+' : '-';
00580 x = fabs( x );
00581 if ( x >= 10.0 ) {
00582 *sIJ++ = '*';
00583 *sIJ++ = ' ';
00584 *sIJ++ = ' ';
00585 }
00586 else if ( x <= ON_SQRT_EPSILON) {
00587 *sIJ++ = '0';
00588 *sIJ++ = ' ';
00589 *sIJ++ = ' ';
00590 }
00591 else if ( x < 0.1) {
00592 *sIJ++ = '~';
00593 *sIJ++ = ' ';
00594 *sIJ++ = ' ';
00595 }
00596 else if ( x < .95 ) {
00597 *sIJ++ = '.';
00598 xi = (int)floor(x*10.0);
00599 if ( xi > 9 )
00600 xi = 9;
00601 else if (xi < 1)
00602 xi = 1;
00603 *sIJ++ = digit[xi];
00604 *sIJ++ = '~';
00605 }
00606 else {
00607 xi = (int)floor(x);
00608 if ( xi < 1 )
00609 xi = 1;
00610 else if (xi > 9)
00611 xi = 9;
00612 *sIJ++ = digit[xi];
00613 if ( x == floor(x) ) {
00614 *sIJ++ = ' ';
00615 *sIJ++ = ' ';
00616 }
00617 else {
00618 *sIJ++ = '.';
00619 *sIJ++ = '~';
00620 }
00621 }
00622 }
00623 }
00624 *sIJ = 0;
00625 Print("%s\n",sRow);
00626 }
00627 }
00628 }
00629
00630 ON_TextLog& ON_TextLog::operator<<(const char* s)
00631 {
00632 Print( "%s", s );
00633 return *this;
00634 }
00635
00636 ON_TextLog& ON_TextLog::operator<<(char c)
00637 {
00638 Print( "%c", c );
00639 return *this;
00640 }
00641
00642 ON_TextLog& ON_TextLog::operator<<(short i)
00643 {
00644 int ii = (int)i;
00645 Print("%d", ii );
00646 return *this;
00647 }
00648
00649 ON_TextLog& ON_TextLog::operator<<(int i)
00650 {
00651 Print("%d",i);
00652 return *this;
00653 }
00654
00655 ON_TextLog& ON_TextLog::operator<<(float x)
00656 {
00657 Print(m_float_format,x);
00658 return *this;
00659 }
00660
00661 ON_TextLog& ON_TextLog::operator<<(double x)
00662 {
00663 Print(m_double_format,x);
00664 return *this;
00665 }
00666
00667 ON_TextLog& ON_TextLog::operator<<( const ON_2dPoint& p )
00668 {
00669 Print(p);
00670 return *this;
00671 }
00672
00673 ON_TextLog& ON_TextLog::operator<<( const ON_3dPoint& p )
00674 {
00675 Print(p);
00676 return *this;
00677 }
00678
00679 ON_TextLog& ON_TextLog::operator<<( const ON_4dPoint& p )
00680 {
00681 Print(p);
00682 return *this;
00683 }
00684
00685 ON_TextLog& ON_TextLog::operator<<( const ON_2dVector& p )
00686 {
00687 Print(p);
00688 return *this;
00689 }
00690
00691 ON_TextLog& ON_TextLog::operator<<( const ON_3dVector& p )
00692 {
00693 Print(p);
00694 return *this;
00695 }
00696
00697 ON_TextLog& ON_TextLog::operator<<( const ON_Xform& xform )
00698 {
00699 Print(xform);
00700 return *this;
00701 }
00702
00703 void ON_TextLog::PrintWrappedText( const char* s, int line_length )
00704 {
00705 ON_wString ws = s;
00706 PrintWrappedText(ws,line_length);
00707 }
00708
00709 static void wsncpy(wchar_t* dst, const wchar_t* src, int n)
00710 {
00711
00712 if ( dst && n > 0 ) {
00713 if ( src ) {
00714 while ( 0 != (*dst++ = *src++) && n-- > 0 );
00715 }
00716 else
00717 *dst = 0;
00718 }
00719 }
00720
00721
00722 void ON_TextLog::PrintWrappedText( const wchar_t* s, int line_length )
00723 {
00724 ON_Workspace ws;
00725 if ( s && *s && line_length > 0 ) {
00726 const int max_line_length = line_length+255;
00727 wchar_t* sLine = (wchar_t*)ws.GetMemory((max_line_length+1)*sizeof(*sLine));
00728 const int wrap_length = line_length;
00729 int i = 0;
00730 int i1 = 0;
00731 int isp = 0;
00732 ON_BOOL32 bPrintLine = false;
00733 while ( s[i] ) {
00734 i1 = i;
00735 if ( s[i] == 10 || s[i] == 13 ) {
00736
00737 i++;
00738 if ( s[i] == 10 && s[i-1] == 13 ) {
00739
00740 i++;
00741 }
00742 bPrintLine = true;
00743 }
00744 else if ( i && s[i] == 32 ) {
00745 if ( !isp ) {
00746 isp = i++;
00747 }
00748 if ( i < wrap_length ) {
00749 isp = i++;
00750 }
00751 else {
00752 bPrintLine = true;
00753 if ( isp ) {
00754 i1 = i = isp;
00755 while ( s[i] == 32 )
00756 i++;
00757 }
00758 else {
00759 i++;
00760 }
00761 }
00762 }
00763 else {
00764 i++;
00765 }
00766 if ( bPrintLine ) {
00767 if ( i1 >= max_line_length )
00768 i1 = max_line_length-1;
00769 if ( i1 > 0 ) {
00770 wsncpy( sLine, s, i1 );
00771 sLine[i1] = 0;
00772 Print( "%ls\n", sLine );
00773 }
00774 else {
00775 Print("\n");
00776 }
00777
00778 s += i;
00779 i = i1 = isp = 0;
00780 bPrintLine = false;
00781 }
00782 }
00783 if ( s[0] ) {
00784 Print( "%ls", s );
00785 }
00786 }
00787 }
00788