Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch improve_looks_like_binary Excluding Merge-Ins
This is equivalent to a diff from ef6c243ed9 to 5963c2dde8
2012-11-02
| ||
02:27 | Merge commit warning and file content type detection changes to trunk. check-in: 0c7c61447f user: mistachkin tags: trunk | |
2012-11-01
| ||
20:09 | Improve detection of UTF-8, UTF-16, binary data, and carriage returns during commit operations. check-in: c837e44445 user: mistachkin tags: commitWarningV2 | |
15:38 | Correct wrong manual merge. Closed-Leaf check-in: 5963c2dde8 user: jan.nijtmans tags: improve_looks_like_binary | |
14:49 | Add back checks for FFFE and FFFF in looks_like_text: - FFFE is a reversed BOM. It could arise when an UTF-16LE and an UTF-16BE file are concatenated. This is always a fatal error, so diff should bail out early. - FFFF is a permanently unassigned character as well, which doesn't exist in any font. Sometimes uninitialized variables are eithe... check-in: 64868f2b98 user: jan.nijtmans tags: improve_looks_like_binary | |
12:32 | merge trunk check-in: 9e97de3410 user: jan.nijtmans tags: use-blob_strip_bom | |
11:48 | merge trunk let looks_like_text() give different values for UTF-16 BE/LE. Not used yet. check-in: 348637dedf user: jan.nijtmans tags: improve_looks_like_binary | |
10:20 | Restore Style fix, which got lost by [618258421767778c] check-in: ef6c243ed9 user: jan.nijtmans tags: trunk | |
07:40 | dont check for same BOM twice check-in: 8c32e6f0dd user: jan.nijtmans tags: trunk | |
Changes to src/checkin.c.
885 885 /* 886 886 ** Issue a warning and give the user an opportunity to abandon out 887 887 ** if a Unicode (UTF-16) byte-order-mark (BOM) or a \r\n line ending 888 888 ** is seen in a text file. 889 889 */ 890 890 static void commit_warning(const Blob *p, int crnlOk, const char *zFilename){ 891 891 int eType; /* return value of looks_like_text() */ 892 - int fUnicode; /* return value of starts_with_utf16_bom() */ 893 892 char *zMsg; /* Warning message */ 894 893 Blob fname; /* Relative pathname of the file */ 895 894 static int allOk = 0; /* Set to true to disable this routine */ 896 895 897 896 if( allOk ) return; 898 897 eType = looks_like_text(p); 899 - fUnicode = starts_with_utf16_bom(p); 900 - if( eType==-1 || fUnicode ){ 901 - const char *zWarning; 898 + if( eType<0 ){ 899 + const char *zWarning ; 902 900 Blob ans; 903 901 char cReply; 904 902 905 - if( eType==-1 && fUnicode ){ 906 - zWarning = "Unicode and CR/NL line endings"; 907 - }else if( eType==-1 ){ 903 + if( eType==-3 ){ 908 904 if( crnlOk ){ 909 905 return; /* We don't want CR/NL warnings for this file. */ 910 906 } 911 907 zWarning = "CR/NL line endings"; 912 908 }else{ 913 909 zWarning = "Unicode"; 914 910 }
Changes to src/diff.c.
46 46 */ 47 47 #define DIFF_CANNOT_COMPUTE_BINARY \ 48 48 "cannot compute difference between binary files\n" 49 49 50 50 #define DIFF_CANNOT_COMPUTE_SYMLINK \ 51 51 "cannot compute difference between symlink and regular file\n" 52 52 53 -#define looks_like_binary(blob) (looks_like_text((blob)) == 0) 53 +#define looks_like_binary(blob) ((looks_like_text(blob)&3) != 1) 54 54 #endif /* INTERFACE */ 55 55 56 56 /* 57 57 ** Maximum length of a line in a text file. (8192) 58 58 */ 59 59 #define LENGTH_MASK_SZ 13 60 60 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) ................................................................................ 177 177 ** values are: 178 178 ** 179 179 ** (1) -- The content appears to consist entirely of text, with lines 180 180 ** delimited by line-feed characters; however, the encoding may 181 181 ** not be UTF-8. 182 182 ** 183 183 ** (0) -- The content appears to be binary because it contains embedded 184 -** NUL (\000) characters or an extremely long line. Since this 185 -** function does not understand UTF-16, it may falsely consider 186 -** UTF-16 text to be binary. 184 +** NUL (\000) characters or an extremely long line. 187 185 ** 188 -** (-1) -- The content appears to consist entirely of text, with lines 186 +** (-1) -- The content appears to consist entirely of text, in the 187 +** UTF-16 (LE) encoding. 188 +** 189 +** (-2) -- The content appears to consist entirely of text, in the 190 +** UTF-16 (BE) encoding. 191 +** 192 +** (-3) -- The content appears to consist entirely of text, with lines 189 193 ** delimited by carriage-return, line-feed pairs; however, the 190 194 ** encoding may not be UTF-8. 191 195 ** 192 196 */ 193 197 int looks_like_text(const Blob *pContent){ 194 - const char *z = blob_buffer(pContent); 198 + unsigned char *z = (unsigned char *) blob_buffer(pContent); 195 199 unsigned int n = blob_size(pContent); 196 - int j, c; 200 + int j; 201 + unsigned char c; 197 202 int result = 1; /* Assume text with no CR/NL */ 198 203 199 204 /* Check individual lines. 200 205 */ 201 206 if( n==0 ) return result; /* Empty file -> text */ 202 207 c = *z; 203 208 if( c==0 ) return 0; /* \000 byte in a file -> binary */ 204 - j = (c!='\n'); 209 + if ( (n&1)==0 ){ /* UTF-16 must have an even blob length */ 210 + if ( (c==0xff) && (z[1]==0xfe) ){ /* UTF-16 LE BOM */ 211 + result = -1; 212 + j = LENGTH_MASK/3; 213 + while( (n-=2)>0 ){ 214 + c = *(z+=2); 215 + if( z[1]==0 ){ /* High-byte must be 0 for further checks */ 216 + if( c==0 ) return 0; /* \000 char in a file -> binary */ 217 + if( c=='\n' ){ 218 + j = LENGTH_MASK/3; 219 + } 220 + }else if( (z[1]==0xff)&&(c>0xfd) ){ 221 + /* FFFE and FFFF are invalid UTF-16. */ 222 + return 0; 223 + } 224 + if( --j==0 ){ 225 + return 0; /* Very long line -> binary */ 226 + } 227 + } 228 + return result; 229 + } else if ( (c==0xfe) && (z[1]==0xff) ){ /* UTF-16 BE BOM */ 230 + result = -2; 231 + ++z; j = LENGTH_MASK/3; 232 + while( (n-=2)>0 ){ 233 + c = *(z+=2); 234 + if ( z[-1]==0 ){ /* High-byte must be 0 for further checks */ 235 + if( c==0 ) return 0; /* \000 char in a file -> binary */ 236 + if( c=='\n' ){ 237 + j = LENGTH_MASK/3; 238 + } 239 + }else if( (z[-1]==0xff)&&(c>0xfd) ){ 240 + /* FFFE and FFFF are invalid UTF-16. */ 241 + return 0; 242 + } 243 + if( --j==0 ){ 244 + return 0; /* Very long line -> binary */ 245 + } 246 + } 247 + return result; 248 + } 249 + } 250 + j = LENGTH_MASK - (c!='\n'); 205 251 while( --n>0 ){ 206 - c = *++z; ++j; 252 + c = *++z; 207 253 if( c==0 ) return 0; /* \000 byte in a file -> binary */ 208 254 if( c=='\n' ){ 209 255 if( z[-1]=='\r' ){ 210 - result = -1; /* Contains CR/NL, continue */ 256 + result = -3; /* Contains CR/NL, continue */ 211 257 } 212 - if( j>LENGTH_MASK ){ 213 - return 0; /* Very long line -> binary */ 214 - } 215 - j = 0; 258 + j = LENGTH_MASK; 259 + } 260 + if( --j==0 ){ 261 + return 0; /* Very long line -> binary */ 216 262 } 217 263 } 218 - if( j>LENGTH_MASK ){ 219 - return 0; /* Very long line -> binary */ 220 - } 221 264 return result; /* No problems seen -> not binary */ 222 265 } 223 266 224 -/* 225 -** This function returns non-zero if the blob starts with a UTF-16le or 226 -** UTF-16be byte-order-mark (BOM). 227 -*/ 228 -int starts_with_utf16_bom(const Blob *pContent){ 229 - const char *z = blob_buffer(pContent); 230 - int c1, c2; 231 - 232 - if( blob_size(pContent)<2 ) return 0; 233 - c1 = z[0]; c2 = z[1]; 234 - if( (c1==(char)0xff) && (c2==(char)0xfe) ){ 235 - return 1; 236 - }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){ 237 - return 1; 238 - } 239 - return 0; 240 -} 241 - 242 267 /* 243 268 ** Return true if two DLine elements are identical. 244 269 */ 245 270 static int same_dline(DLine *pA, DLine *pB){ 246 271 return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0; 247 272 } 248 273
Changes to src/doc.c.
24 24 25 25 /* 26 26 ** Try to guess the mimetype from content. 27 27 ** 28 28 ** If the content is pure text, return NULL. 29 29 ** 30 30 ** For image types, attempt to return an appropriate mimetype 31 -** name like "image/gif" or "image/jpeg". 31 +** name like "image/gif" or "image/jpeg". 32 32 ** 33 33 ** For any other binary type, return "unknown/unknown". 34 34 */ 35 35 const char *mimetype_from_content(Blob *pBlob){ 36 36 int i; 37 37 int n; 38 38 const unsigned char *x; 39 39 40 - static const char isBinary[] = { 41 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 42 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 40 + static const char isBinary[256] = { 41 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 42 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 43 43 }; 44 44 45 45 /* A table of mimetypes based on file content prefixes 46 46 */ 47 47 static const struct { 48 48 const char *zPrefix; /* The file prefix */ 49 49 int size; /* Length of the prefix */ ................................................................................ 56 56 { "\377\330\377", 3, "image/jpeg" }, 57 57 }; 58 58 59 59 x = (const unsigned char*)blob_buffer(pBlob); 60 60 n = blob_size(pBlob); 61 61 for(i=0; i<n; i++){ 62 62 unsigned char c = x[i]; 63 - if( c<=0x1f && isBinary[c] ){ 63 + if( isBinary[c] ){ 64 64 break; 65 65 } 66 66 } 67 67 if( i>=n ){ 68 68 return 0; /* Plain text */ 69 69 } 70 70 for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){ ................................................................................ 81 81 const char *mimetype_from_name(const char *zName){ 82 82 const char *z; 83 83 int i; 84 84 int first, last; 85 85 int len; 86 86 char zSuffix[20]; 87 87 88 - /* A table of mimetypes based on file suffixes. 88 + /* A table of mimetypes based on file suffixes. 89 89 ** Suffixes must be in sorted order so that we can do a binary 90 90 ** search to find the mime-type 91 91 */ 92 92 static const struct { 93 93 const char *zSuffix; /* The file suffix */ 94 94 int size; /* Length of the suffix */ 95 95 const char *zMimetype; /* The corresponding mimetype */ ................................................................................ 472 472 if( content_get(rid, &filebody)==0 ){ 473 473 goto doc_not_found; 474 474 } 475 475 db_end_transaction(0); 476 476 } 477 477 478 478 /* The file is now contained in the filebody blob. Deliver the 479 - ** file to the user 479 + ** file to the user 480 480 */ 481 481 zMime = P("mimetype"); 482 482 if( zMime==0 ){ 483 483 zMime = mimetype_from_name(zName); 484 484 } 485 485 Th_Store("doc_name", zName); 486 486 Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'" ................................................................................ 511 511 512 512 doc_not_found: 513 513 /* Jump here when unable to locate the document */ 514 514 db_end_transaction(0); 515 515 style_header("Document Not Found"); 516 516 @ <p>No such document: %h(zName)</p> 517 517 style_footer(); 518 - return; 518 + return; 519 519 } 520 520 521 521 /* 522 522 ** The default logo. 523 523 */ 524 524 static const unsigned char aLogo[] = { 525 - 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85, 526 - 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166, 527 - 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, 528 - 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, 529 - 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, 530 - 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0, 531 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 532 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 533 - 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105, 534 - 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56, 535 - 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161, 536 - 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102, 537 - 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242, 538 - 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233, 539 - 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8, 540 - 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6, 541 - 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5, 542 - 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40, 543 - 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40, 544 - 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201, 545 - 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19, 546 - 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100, 547 - 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195, 548 - 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158, 549 - 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176, 550 - 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194, 551 - 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244, 552 - 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182, 553 - 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130, 554 - 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137, 555 - 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224, 556 - 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40, 557 - 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96, 558 - 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250, 559 - 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170, 560 - 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91, 561 - 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219, 562 - 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189, 563 - 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10, 564 - 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17, 565 - 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203, 566 - 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241, 567 - 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141, 568 - 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188, 569 - 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24, 570 - 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2, 571 - 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128, 572 - 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129, 573 - 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196, 574 - 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196, 575 - 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143, 576 - 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131, 577 - 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224, 578 - 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16, 579 - 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66, 580 - 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154, 581 - 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94, 582 - 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197, 583 - 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86, 584 - 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159, 585 - 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13, 586 - 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59, 525 + 71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85, 526 + 129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166, 527 + 116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, 528 + 195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, 529 + 215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, 530 + 233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0, 531 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 532 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 533 + 0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105, 534 + 158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56, 535 + 16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161, 536 + 82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102, 537 + 181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242, 538 + 87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233, 539 + 131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8, 540 + 19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6, 541 + 143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5, 542 + 22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40, 543 + 167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40, 544 + 19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201, 545 + 189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19, 546 + 3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100, 547 + 5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195, 548 + 177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158, 549 + 2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176, 550 + 145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194, 551 + 19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244, 552 + 43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182, 553 + 54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130, 554 + 176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137, 555 + 19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224, 556 + 50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40, 557 + 174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96, 558 + 148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250, 559 + 69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170, 560 + 47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91, 561 + 232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219, 562 + 10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189, 563 + 229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10, 564 + 18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17, 565 + 239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203, 566 + 183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241, 567 + 230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141, 568 + 84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188, 569 + 15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24, 570 + 184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2, 571 + 13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128, 572 + 16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129, 573 + 205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196, 574 + 5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196, 575 + 153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143, 576 + 105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131, 577 + 16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224, 578 + 159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16, 579 + 36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66, 580 + 64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154, 581 + 49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94, 582 + 3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197, 583 + 138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86, 584 + 233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159, 585 + 214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13, 586 + 27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59, 587 587 }; 588 588 589 589 /* 590 590 ** WEBPAGE: logo 591 591 ** 592 592 ** Return the logo image. This image is available to anybody who can see 593 593 ** the login page. It is designed for use in the upper left-hand corner