Annotation of XNU/iokit/Tests/TestContainers.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: #if DEBUG
                     23: #include "Tests.h"
                     24: 
                     25: #include <libkern/c++/OSData.h>
                     26: #include <libkern/c++/OSString.h>
                     27: #include <libkern/c++/OSSymbol.h>
                     28: 
                     29: static const char testC00[] = "The quick brown fox jumps over the lazy dog.  ";
                     30: static const char testC01[] = "The quick brown fox ";
                     31: static const char testC02[] = "jumps over the ";
                     32: static const char testC03[] = "lazy dog.  \n";
                     33: static const char testC04[] = "The ";
                     34: static const char testC05[] = "quick ";
                     35: static const char testC06[] = "brown ";
                     36: static const char testC07[] = "fox ";
                     37: static const char testC08[] = "jumps ";
                     38: static const char testC09[] = "over ";
                     39: static const char testC10[] = "the ";
                     40: static const char testC11[] = "lazy ";
                     41: static const char testC12[] = "dog.  \n";
                     42: static const char testC13[] = "Now is the time for all good "
                     43:                                "men to come to the aid of the party  \n";
                     44: static const char testC14[] = "Now is the time for ";
                     45: static const char testC15[] = "all good men to come ";
                     46: static const char testC16[] = "to the aid of the party  \n";
                     47: static const char testC17[] = "Now ";
                     48: static const char testC18[] = "is ";
                     49: static const char testC19[] = "the ";
                     50: static const char testC20[] = "time ";
                     51: static const char testC21[] = "for ";
                     52: static const char testC22[] = "all ";
                     53: static const char testC23[] = "good ";
                     54: static const char testC24[] = "men ";
                     55: static const char testC25[] = "to ";
                     56: static const char testC26[] = "come ";
                     57: static const char testC27[] = "to ";
                     58: static const char testC28[] = "the ";
                     59: static const char testC29[] = "aid ";
                     60: static const char testC30[] = "of ";
                     61: static const char testC31[] = "the ";
                     62: static const char testC32[] = "party.  \n";
                     63: static const char testC33[] = "Frank Burns eats worms.  \n";
                     64: static const char testC34[] = "Frank Burns ";
                     65: static const char testC35[] = "eats worms.  \n";
                     66: static const char testC36[] = "Frank ";
                     67: static const char testC37[] = "Burns ";
                     68: static const char testC38[] = "eats ";
                     69: static const char testC39[] = "worms.  \n";
                     70: static const char testC40[] = "Tired eyes?  Stiff neck?  Tight shoulders?  "
                     71:                               "Aching back?  The right moves can help "
                     72:                               "prevent these kinds of problem.  ";
                     73: static const char testC41[] = "Tired eyes?  Stiff neck?  ";
                     74: static const char testC42[] = "Tight shoulders?  Aching back?  ";
                     75: static const char testC43[] = "The right moves can help prevent ";
                     76: static const char testC44[] = "these kinds of problem.  ";
                     77: static const char testC45[] = "Tired ";
                     78: static const char testC46[] = "eyes?  ";
                     79: static const char testC47[] = "Stiff ";
                     80: static const char testC48[] = "neck?  ";
                     81: static const char testC49[] = "Tight ";
                     82: static const char testC50[] = "shoulders?  ";
                     83: static const char testC51[] = "Aching ";
                     84: static const char testC52[] = "back?  ";
                     85: static const char testC53[] = "The ";
                     86: static const char testC54[] = "right ";
                     87: static const char testC55[] = "moves ";
                     88: static const char testC56[] = "can ";
                     89: static const char testC57[] = "help ";
                     90: static const char testC58[] = "prevent ";
                     91: static const char testC59[] = "these ";
                     92: static const char testC60[] = "kinds ";
                     93: static const char testC61[] = "of ";
                     94: static const char testC62[] = "problem.  ";
                     95: 
                     96: const char *strCache[] = {
                     97:     testC00, testC01, testC02, testC03, testC04, testC05, testC06, testC07,
                     98:     testC08, testC09, testC10, testC11, testC12, testC13, testC14, testC15,
                     99:     testC16, testC17, testC18, testC19, testC20, testC21, testC22, testC23,
                    100:     testC24, testC25, testC26, testC27, testC28, testC29, testC30, testC31,
                    101:     testC32, testC33, testC34, testC35, testC36, testC37, testC38, testC39, 
                    102:     testC40, testC41, testC42, testC43, testC44, testC45, testC46, testC47, 
                    103:     testC48, testC49, testC50, testC51, testC52, testC53, testC54, testC55, 
                    104:     testC56, testC57, testC58, testC59, testC60, testC61, testC62, 
                    105: };
                    106: const int numStrCache = ((int) (sizeof(strCache)/sizeof(strCache[0])));
                    107: 
                    108: void testData()
                    109: {
                    110: #define DATA_SIZE_1     256
                    111: #define DATA_SIZE_2     512
                    112: #define DATA_SIZE_3    1024
                    113: #define DATA_SIZE_4    8192
                    114:     
                    115:     OSData *test1, *test2, *test3;
                    116:     void *spaceCheck;
                    117:     unsigned int len;
                    118:     unsigned int i;
                    119:     bool res = true;
                    120:     unsigned short testData[DATA_SIZE_4/sizeof(short)], *cp;
                    121: 
                    122:     // very first test initialises the OSMetaClass cache.
                    123:     test1 = OSData::withCapacity(DATA_SIZE_1);
                    124:     TEST_ASSERT('d', "0a", test1);
                    125:     if (test1)
                    126:         test1->release();
                    127: 
                    128:     for (i = 0; i < sizeof(testData)/sizeof(short); i++)
                    129:         testData[i] = (unsigned short) i;
                    130: 
                    131:     // Check empty data allocation
                    132:     spaceCheck = checkPointSpace();
                    133:     test1 = OSData::withCapacity(DATA_SIZE_1);
                    134:     TEST_ASSERT('d', "1a", test1);
                    135:     if (test1) {
                    136:         TEST_ASSERT('d', "1b", !test1->getLength());
                    137:         TEST_ASSERT('d', "1c", test1->getCapacity() == DATA_SIZE_1);
                    138:         TEST_ASSERT('d', "1d", !test1->getBytesNoCopy());
                    139:         TEST_ASSERT('d', "1e", !test1->getBytesNoCopy(10, DATA_SIZE_1 - 10));
                    140:         TEST_ASSERT('d', "1f", test1->appendBytes(spaceCheck, 0));
                    141:         TEST_ASSERT('d', "1g", !test1->getLength());
                    142:         TEST_ASSERT('d', "1h", test1->getCapacity() == DATA_SIZE_1);
                    143:         TEST_ASSERT('d', "1i", !test1->getBytesNoCopy());
                    144:         test1->release();
                    145:     }
                    146:     res = res && checkSpace("(d)1", spaceCheck, 0);
                    147: 
                    148:     // Check appending to empty data allocation 
                    149:     spaceCheck = checkPointSpace();
                    150:     test1 = OSData::withCapacity(DATA_SIZE_1);
                    151:     TEST_ASSERT('d', "2a", test1);
                    152:     if (test1) {
                    153:         TEST_ASSERT('d', "2b", !test1->getLength());
                    154:         TEST_ASSERT('d', "2c", !test1->getBytesNoCopy());
                    155:         TEST_ASSERT('d', "2d", test1->appendBytes(testData, DATA_SIZE_1));
                    156:         TEST_ASSERT('d', "2e", test1->getLength() == DATA_SIZE_1);
                    157:         TEST_ASSERT('d', "2f", test1->getBytesNoCopy());
                    158:         cp = (unsigned short *) test1->getBytesNoCopy();
                    159:         for (i = 0; cp && i < (DATA_SIZE_1/sizeof(short)); i++) {
                    160:             TEST_ASSERT('d', "2g", *cp++ == testData[i]);
                    161:             if (*cp != testData[i])
                    162:                 break;
                    163:         }
                    164:         TEST_ASSERT('d', "2h", test1->getBytesNoCopy(10, DATA_SIZE_1-10));
                    165:         cp = (unsigned short *) test1->getBytesNoCopy(10, DATA_SIZE_1 - 10);
                    166:         for (i = 5; cp && i < (DATA_SIZE_1/sizeof(short)) - 5; i++) {
                    167:             TEST_ASSERT('d', "2i", *cp++ == testData[i]);
                    168:             if (*cp != testData[i])
                    169:                 break;
                    170:         }
                    171:         TEST_ASSERT('d', "2j", test1->isEqualTo(testData, DATA_SIZE_1));
                    172:         test1->release();
                    173:     }
                    174:     res = res && checkSpace("(d)2", spaceCheck, 0);
                    175: 
                    176:     // Check data allocation from some constant data
                    177:     spaceCheck = checkPointSpace();
                    178:     test1 = OSData::withBytes(testData, sizeof(testData));
                    179:     TEST_ASSERT('d', "3a", test1);
                    180:     if (test1) {
                    181:         TEST_ASSERT('d', "3b", test1->getLength() == sizeof(testData));
                    182:         TEST_ASSERT('d', "3c", test1->getCapacity() == sizeof(testData));
                    183:         TEST_ASSERT('d', "3d", test1->getBytesNoCopy());
                    184:         TEST_ASSERT('d', "3e", test1->getBytesNoCopy(10, sizeof(testData)-10));
                    185:         TEST_ASSERT('d', "3f", test1->appendBytes(spaceCheck, 0));
                    186:         TEST_ASSERT('d', "3g", test1->getLength() == sizeof(testData));
                    187:         TEST_ASSERT('d', "3h", test1->getCapacity() == sizeof(testData));
                    188:         TEST_ASSERT('d', "3i", test1->getBytesNoCopy());
                    189:         TEST_ASSERT('d', "3j", test1->getBytesNoCopy(10, sizeof(testData)-10));
                    190:         TEST_ASSERT('d', "3k", !test1->appendBytes(testData, 10));
                    191:         test1->release();
                    192:     }
                    193:     res = res && checkSpace("(d)3", spaceCheck, 0);
                    194: 
                    195:     // Check and continious addition of more data
                    196:     spaceCheck = checkPointSpace();
                    197:     test1 = OSData::withCapacity(DATA_SIZE_4);
                    198:     test2 = OSData::withBytesNoCopy(testData, DATA_SIZE_3);
                    199:     len = DATA_SIZE_3;
                    200:     TEST_ASSERT('d', "4a", (test1 && test2));
                    201:     if (test1 && test2) {
                    202:         TEST_ASSERT('d', "4b", !test1->getLength());
                    203:         for (i = 0; i < DATA_SIZE_4; i += DATA_SIZE_3)
                    204:             TEST_ASSERT('d', "4c", test1->appendBytes(test2));
                    205:         TEST_ASSERT('d', "4d", !test1->appendBytes(test2));
                    206:         for (i = 0; i < DATA_SIZE_4; i += DATA_SIZE_3) {
                    207: 
                    208:             TEST_ASSERT('d', "4e", test2->isEqualTo(
                    209:                                         test1->getBytesNoCopy(i, DATA_SIZE_3),
                    210:                                         DATA_SIZE_3));
                    211: 
                    212:             test3 = OSData::withData(test1, i, DATA_SIZE_3);
                    213:             TEST_ASSERT('d', "4f", test3);
                    214:             if (test3) {
                    215:                 TEST_ASSERT('d', "4g", test2->isEqualTo(test3));
                    216:                 test3->release();
                    217:             }
                    218: 
                    219:             test3 = OSData::withData(test1, i, len);
                    220:             TEST_ASSERT('d', "4i", test3);
                    221:             if (test3) {
                    222:                 TEST_ASSERT('d', "4j", test2->isEqualTo(test3));
                    223:                 test3->release();
                    224:             }
                    225:         }
                    226:         test1->release();
                    227:         test2->release();
                    228:     }
                    229:     res = res && checkSpace("(d)3", spaceCheck, 0);
                    230: 
                    231:     if (res)
                    232:         verPrintf(("testData: All OSData Tests passed\n"));
                    233:     else
                    234:         logPrintf(("testData: Some OSData Tests failed\n"));
                    235: #undef DATA_SIZE_4
                    236: #undef DATA_SIZE_3
                    237: #undef DATA_SIZE_2
                    238: #undef DATA_SIZE_1
                    239: }
                    240: 
                    241: void testString()
                    242: {
                    243:     OSString *test1, *test2;
                    244:     void *spaceCheck;
                    245:     int i;
                    246:     char c;
                    247:     bool res = true;
                    248: 
                    249:     // very first test initialises the OSMetaClass cache.
                    250:     test1 = OSString::withCStringNoCopy(testC00);
                    251:     TEST_ASSERT('s', "0a", test1);
                    252:     if (test1)
                    253:         test1->release();
                    254: 
                    255:     // Check c string allocation
                    256:     spaceCheck = checkPointSpace();
                    257:     test1 = OSString::withCString(testC00);
                    258:     TEST_ASSERT('s', "1a", test1);
                    259:     TEST_ASSERT('s', "1b", testC00 != test1->getCStringNoCopy());
                    260:     TEST_ASSERT('s', "1c", strcmp(testC00, test1->getCStringNoCopy()) == 0);
                    261:     TEST_ASSERT('s', "1d", strlen(testC00) == test1->getLength());
                    262:     TEST_ASSERT('s', "1e", test1->isEqualTo(testC00));
                    263:     TEST_ASSERT('s', "1f", !test1->isEqualTo(testC01));
                    264:     if (test1) test1->release();
                    265:     res = res && checkSpace("(s)1", spaceCheck, 0);
                    266: 
                    267:     // Check c string no allocation
                    268:     spaceCheck = checkPointSpace();
                    269:     test1 = OSString::withCStringNoCopy(testC00);
                    270:     TEST_ASSERT('s', "2a", test1);
                    271:     TEST_ASSERT('s', "2b", testC00 == test1->getCStringNoCopy());
                    272:     if (test1) test1->release();
                    273:     res = res && checkSpace("(s)2", spaceCheck, 0);
                    274: 
                    275:     // Check string from other string generation
                    276:     spaceCheck = checkPointSpace();
                    277:     test1 = OSString::withCStringNoCopy(testC00);
                    278:     TEST_ASSERT('s', "3a", test1);
                    279:     test2 = OSString::withString(test1);
                    280:     TEST_ASSERT('s', "3b", test2);
                    281:     TEST_ASSERT('s', "3c", test1 != test2);
                    282:     TEST_ASSERT('s', "3d", test1->isEqualTo(test2));
                    283:     if (test1) test1->release();
                    284:     if (test2) test2->release();
                    285:     res = res && checkSpace("(s)3", spaceCheck, 0);
                    286: 
                    287:     // Check string comparison functionality no copy
                    288:     spaceCheck = checkPointSpace();
                    289:     test1 = OSString::withCStringNoCopy(testC00);
                    290:     test2 = OSString::withCStringNoCopy(testC01);
                    291:     TEST_ASSERT('s', "4a", test1 && test2);
                    292:     TEST_ASSERT('s', "4b", !test1->isEqualTo(test2));
                    293:     TEST_ASSERT('s', "4c", !test1->isEqualTo(testC01));
                    294:     TEST_ASSERT('s', "4d", test1->isEqualTo(testC00));
                    295:     if (test1) test1->release();
                    296:     if (test2) test2->release();
                    297:     res = res && checkSpace("(s)4", spaceCheck, 0);
                    298: 
                    299:     // Check string comparison functionality with copy
                    300:     spaceCheck = checkPointSpace();
                    301:     test1 = OSString::withCString(testC00);
                    302:     test2 = OSString::withCString(testC01);
                    303:     TEST_ASSERT('s', "5a", test1 && test2);
                    304:     TEST_ASSERT('s', "5b", !test1->isEqualTo(test2));
                    305:     TEST_ASSERT('s', "5c", !test1->isEqualTo(testC01));
                    306:     TEST_ASSERT('s', "5d", test1->isEqualTo(testC00));
                    307:     if (test1) test1->release();
                    308:     if (test2) test2->release();
                    309:     res = res && checkSpace("(s)5", spaceCheck, 0);
                    310: 
                    311:     // Check string inplace modifications
                    312:     spaceCheck = checkPointSpace();
                    313:     test1 = OSString::withCString(testC00);
                    314:     TEST_ASSERT('s', "6a", test1);
                    315:     for (i = 0; (c = test1->getChar(i)); i++)
                    316:         if (c != testC00[i]) {
                    317:             verPrintf(("testString(s) test 6b failed\n")); res = false;
                    318:             break;
                    319:         }
                    320:     TEST_ASSERT('s', "6c", !c);
                    321:     TEST_ASSERT('s', "6d", test1->setChar(' ', 0));
                    322:     TEST_ASSERT('s', "6e", !test1->isEqualTo(testC00));
                    323:     TEST_ASSERT('s', "6f", test1->setChar('T', 0));
                    324:     TEST_ASSERT('s', "6g", !test1->setChar(' ', sizeof(testC00)));
                    325:     TEST_ASSERT('s', "6h", test1->isEqualTo(testC00));
                    326:     if (test1) test1->release();
                    327:     res = res && checkSpace("(s)6", spaceCheck, 0);
                    328: 
                    329:     // Check const string fail inplace modifications
                    330:     spaceCheck = checkPointSpace();
                    331:     test1 = OSString::withCStringNoCopy(testC00);
                    332:     TEST_ASSERT('s', "7a", test1);
                    333:     for (i = 0; (c = test1->getChar(i)); i++)
                    334:         if (c != testC00[i]) {
                    335:             verPrintf(("testString(s) test 7b failed\n")); res = false;
                    336:             break;
                    337:         }
                    338:     TEST_ASSERT('s', "7c", !c);
                    339:     TEST_ASSERT('s', "7d", !test1->setChar(' ', 0));
                    340:     TEST_ASSERT('s', "7e", test1->isEqualTo(testC00));
                    341:     TEST_ASSERT('s', "7f", !test1->setChar(' ', sizeof(testC00)));
                    342:     TEST_ASSERT('s', "7g", test1->isEqualTo(testC00));
                    343:     if (test1) test1->release();
                    344:     res = res && checkSpace("(s)7", spaceCheck, 0);
                    345: 
                    346:     if (res)
                    347:         verPrintf(("testString: All OSString Tests passed\n"));
                    348:     else
                    349:         logPrintf(("testString: Some OSString Tests failed\n"));
                    350: }
                    351: 
                    352: void testSymbol()
                    353: {
                    354:     bool res = true;
                    355:     int i, j;
                    356:     int countDups;
                    357:     const OSSymbol *cache[numStrCache];
                    358:     void *spaceCheck;
                    359: 
                    360:     // very first test initialises the OSMetaClass cache.
                    361:     cache[0] = IOSymbol::withCStringNoCopy(testC00);
                    362:     TEST_ASSERT('u', "0a", cache[0]);
                    363:     if (cache[0])
                    364:         cache[0]->release();
                    365: 
                    366:     spaceCheck = checkPointSpace();
                    367: 
                    368:     // Setup the symbol cache, make sure it grows the symbol unique'ing
                    369:     // hash table.  Also determine that the symbol is created ok and that
                    370:     // it is indeed equal to the creating cString by strcmp.
                    371:     for (i = 0; i < numStrCache; i++) {
                    372:         cache[i] = OSSymbol::withCStringNoCopy(strCache[i]);
                    373:         if (!cache[i]) {
                    374:             verPrintf(("testSymbol(u) test 1a%d failed\n", i)); res = false;
                    375:         }
                    376:         else if (!cache[i]->isEqualTo(strCache[i])) {
                    377:             verPrintf(("testSymbol(u) test 1b%d failed\n", i)); res = false;
                    378:         }
                    379:     }
                    380: 
                    381:     // The strCache does have some duplicates in it, mostly 'the'.  Make
                    382:     // sure that we wind them and that different cache entries really are
                    383:     // different by strcmp.  Fundamental to OSSymbol semantics.
                    384:     countDups = 0;
                    385:     for (i = 0; i < numStrCache; i++)
                    386:         for (j = i+1; j < numStrCache; j++) {
                    387:             if (cache[i] != cache[j] && cache[i]->isEqualTo(cache[j])) {
                    388:                 verPrintf(("testSymbol(u) test 2a%d,%d failed\n", i, j));
                    389:                 res = false;
                    390:             }
                    391:             else if (cache[i] == cache[j]) {
                    392:                 if (cache[i]->getRetainCount() == 1) {
                    393:                     verPrintf(("testSymbol(u) test 2b%d,%d failed\n", i, j));
                    394:                     res = false;
                    395:                 }
                    396:                 countDups++;
                    397:             }
                    398:         }
                    399:     TEST_ASSERT('u', "2c", countDups);
                    400: 
                    401:     // Clear out the cache and check that the unique'ing hashtable has grown
                    402:     for (i = 0; i < numStrCache; i++) {
                    403:         if (cache[i]) {
                    404:             cache[i]->release();
                    405:             cache[i] = 0;
                    406:         }
                    407:     }
                    408:     // As of 1998-11-17 the hash growth is 364.
                    409:     res = res && checkSpace("(u)3", spaceCheck, 972);
                    410:     logSpace();
                    411: 
                    412:     // Check for leaks by repeating the cacheing and freeing
                    413:     spaceCheck = checkPointSpace();
                    414:     for (i = 0; i < numStrCache; i++)
                    415:         cache[i] = OSSymbol::withCString(strCache[i]);
                    416:     for (i = 0; i < numStrCache; i++) {
                    417:         if (cache[i]) {
                    418:             cache[i]->release();
                    419:             cache[i] = 0;
                    420:         }
                    421:     }
                    422:     res = res && checkSpace("(u)4", spaceCheck, 0);
                    423: 
                    424:     // Check that the OSString based symbol constructors work
                    425:     // and that they don't leak, and finally double check that while
                    426:     // the cache is active the symbol semantics still work.
                    427:     spaceCheck = checkPointSpace();
                    428:     for (i = 0; i < numStrCache; i++) {
                    429:         OSString *tmpStr;
                    430: 
                    431:         tmpStr = (i&1)
                    432:                ? OSString::withCString(strCache[i])
                    433:                : OSString::withCStringNoCopy(strCache[i]);
                    434:         if (tmpStr) {
                    435:             cache[i] = OSSymbol::withString(tmpStr);
                    436:             if (!cache[i]) {
                    437:                 verPrintf(("testSymbol(u) test 5a%d failed\n", i));
                    438:                 res = false;
                    439:             }
                    440:             tmpStr->release();
                    441:         }
                    442:     }
                    443: 
                    444:     for (i = 0; i < numStrCache; i++) {
                    445:         if (cache[i]) {
                    446:             const OSSymbol *tmpSymb;
                    447: 
                    448:             tmpSymb = OSSymbol::withCStringNoCopy(strCache[i]);
                    449:             if (cache[i] != tmpSymb) {
                    450:                 verPrintf(("testSymbol(u) test 5b%d failed\n", i));
                    451:                 res = false;
                    452:             }
                    453:             tmpSymb->release();
                    454:             cache[i]->release();
                    455:             cache[i] = 0;
                    456:         }
                    457:         else {
                    458:             verPrintf(("testSymbol(u) test 5c%d failed\n", i));
                    459:             res = false;
                    460:         }
                    461:     }
                    462:     res = res && checkSpace("(u)5", spaceCheck, 0);
                    463: 
                    464:     if (res)
                    465:         verPrintf(("testSymbol: All OSSymbol Tests passed\n"));
                    466:     else
                    467:         logPrintf(("testSymbol: Some OSSymbol Tests failed\n"));
                    468: }
                    469: 
                    470: #endif /* DEBUG */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.