Annotation of researchv10dc/cmd/icon/src/iconx/rmemmon.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * File: rmemmon.c
        !             3:  *  Contents: gd, memmon
        !             4:  */
        !             5: 
        !             6: /*
        !             7:  * gd.c - graphics driver for AED 1024.
        !             8:  *  Rewrite this file to use a different output device.
        !             9:  *
        !            10:  *  Except for gdwidth(), which is used only for layout, these functions
        !            11:  *  provide a ONE-DIMENSIONAL interface to the AED.
        !            12:  */
        !            13: 
        !            14: #include "../h/rt.h"
        !            15: #include "gc.h"
        !            16: 
        !            17: #ifdef MemMon
        !            18: 
        !            19: #include <sgtty.h>
        !            20: #include <varargs.h>
        !            21: 
        !            22: #define Height 768                     /* screen height */
        !            23: #define Width 1024                     /* screen width */
        !            24: #define PromptArea 50                  /* pixels to reserve for prompting */
        !            25: #define PromptSize 40                  /* size of prompt block proper */
        !            26: #define MaxColors 256                  /* maximum number of distinct colors */
        !            27: #define MaxScale 16                    /* maximum scaling factor */
        !            28: #define EndRun() if(runaddr)putc(runaddr=0,ofile);  /* end a run of pixels */
        !            29: 
        !            30: static FILE *ifile = 0;                        /* AED input file */
        !            31: static FILE *ofile = 0;                        /* AED output file */
        !            32: static int yscale = 1;                 /* vertical scaling factor */
        !            33: static int npixels = Height * Width - PromptArea;  /* screen size (scaled) */
        !            34: static runaddr = 0;                    /* curr addr if pixel run in progress */
        !            35: static int bgcolor;                    /* current background color */
        !            36: 
        !            37: /*
        !            38:  * gdinit(filename) - initialize for graphics output.
        !            39:  */
        !            40: 
        !            41: gdinit(fname)
        !            42: char *fname;
        !            43:    {
        !            44:    FILE *newf;
        !            45:    int ofd;
        !            46:    struct sgttyb ttyb;
        !            47:    static int ldisc = NTTYDISC;
        !            48:    static int lbits = LLITOUT;
        !            49: 
        !            50:    if ((newf = fopen(fname,"w")) == NULL)
        !            51:       error("can't open MemMon file");
        !            52:    if (isatty(ofd = fileno(newf)))  {
        !            53:       if (ioctl(ofd, TIOCSETD, &ldisc))
        !            54:          error("can't select new tty driver for MemMon file");
        !            55:       if (ioctl(ofd, TIOCGETP, &ttyb))
        !            56:          error("can't get sgtty block for MemMon file");
        !            57:       if (ioctl(ofd, TIOCLBIS, &lbits))
        !            58:          error("can't set LLITOUT on MemMon file");
        !            59:       ttyb.sg_flags &= ~(RAW+ECHO);
        !            60:       if (ioctl(ofd, TIOCSETP, &ttyb))
        !            61:          error("can't set tty attributes for MemMon file");
        !            62:       if (ifile = fopen(fname,"r")) {
        !            63: #ifndef VMS
        !            64:          setbuf(ifile,NULL);
        !            65: #endif VMS
        !            66:         }
        !            67:       else {
        !            68:          fprintf(stderr, "can't read MemMon file;  will not pause\n");
        !            69:         fflush(stderr);
        !            70:         }
        !            71:       }
        !            72:    ofile = newf;
        !            73:    fputs("\033SEN18D88",ofile);        /* set encoding mode to binary */
        !            74:    aedout("gii",0,767);                /* set normal window boundaries */
        !            75: }
        !            76: 
        !            77: /*
        !            78:  * gdmap(array,n) - set color map.  Each entry of array (of size n) has three
        !            79:  *  bits each of red, green, blue values in least signifigant bits.  The
        !            80:  *  constants in the table below were determined empirically.
        !            81:  */
        !            82: 
        !            83: gdmap(a,n)
        !            84: int a[], n;
        !            85:    {
        !            86:    unsigned char buf[3*MaxColors+4];
        !            87:    unsigned char *p;
        !            88:    static unsigned char rmap[] = { 0, 20, 45, 70, 100, 140, 190, 255};
        !            89:    static unsigned char gmap[] = { 0, 40, 60, 80, 110, 150, 195, 255};
        !            90:    static unsigned char bmap[] = { 0, 40, 60, 80, 110, 150, 195, 255};
        !            91: 
        !            92:    EndRun();
        !            93:    p = buf;
        !            94:    *p++ = 'K';
        !            95:    *p++ = 0;
        !            96:    *p++ = n;
        !            97:    while (n--)  {
        !            98:       *p++ = rmap [ *a >> 6 ];
        !            99:       *p++ = gmap [ (*a >> 3) & 7 ];
        !           100:       *p++ = bmap [ *a++ & 7 ];
        !           101:       }
        !           102:    fwrite(buf,1,p-buf,ofile);
        !           103:    }
        !           104: 
        !           105: /*
        !           106:  * gdflood(c) - fill screen with color c.
        !           107:  */
        !           108: 
        !           109: gdflood(c)
        !           110: int c;
        !           111:    {
        !           112:    EndRun();
        !           113:    aedout("[b",c);                     /* set background color */
        !           114:    aedout("~");                                /* erase screen (kills scaling) */
        !           115:    aedout("Ebb",1,yscale);             /* reset scaling */
        !           116:    bgcolor = c;                                /* save background color */
        !           117:    }
        !           118: 
        !           119: /*
        !           120:  * gdscale(n) - set vertical scaling factor.
        !           121:  */
        !           122: 
        !           123: gdscale(n)
        !           124: int n;
        !           125:    {
        !           126:    EndRun();
        !           127:    if (n > MaxScale)
        !           128:       n = MaxScale;
        !           129:    yscale = n;
        !           130:    npixels = (Height / n) * Width - PromptArea;
        !           131:    aedout("Ebb",1,n);          /* set zoom to handle y scaling (only!) */
        !           132:    }
        !           133: 
        !           134: /*
        !           135:  * gdsize(n) - return size of display with scaling factor n;
        !           136:  */
        !           137: 
        !           138: gdsize(n)
        !           139: int n;
        !           140:    {
        !           141:    if (n > MaxScale)
        !           142:       n = MaxScale;
        !           143:    return (Height / n) * Width - PromptArea;
        !           144:    }
        !           145: 
        !           146: /*
        !           147:  * gdwidth() - return width of display with current scaling.
        !           148:  */
        !           149: 
        !           150: gdwidth()
        !           151:    {
        !           152:    return Width;
        !           153:    }
        !           154: 
        !           155: /*
        !           156:  * gdpaint(start,n,color,b) - paint n pixels in given color.
        !           157:  *  If b >= 0, the last pixel is to be that color instead (for a border)
        !           158:  */
        !           159: 
        !           160: gdpaint(s,n,c,b)
        !           161: int s, n, c, b;
        !           162:    {
        !           163:    if (s < 0 || s >= npixels || n <= 0)
        !           164:       return;
        !           165:    if (s + n > npixels)
        !           166:       n = npixels - s;
        !           167:    if (runaddr && runaddr != s)
        !           168:       putc(runaddr=0,ofile);
        !           169:    if (!runaddr)  {
        !           170:       aedout("Qx", s % Width, Height - 1 - s / Width);
        !           171:       aedout("s");
        !           172:       }
        !           173:    runaddr = s + n;
        !           174:    if (b >= 0)
        !           175:       n--;
        !           176:    while (n > 254)  {
        !           177:       putc(254,ofile);
        !           178:       putc(c,ofile);
        !           179:       n -= 254;
        !           180:       }
        !           181:    if (n > 0)  {
        !           182:       putc(n,ofile);
        !           183:       putc(c,ofile);
        !           184:       }
        !           185:    if (b >= 0)  {
        !           186:       putc(1,ofile);
        !           187:       putc(b,ofile);
        !           188:       }
        !           189:    }
        !           190: 
        !           191: /*
        !           192:  * gdflush() - flush output.
        !           193:  */
        !           194: 
        !           195: gdflush()
        !           196:    {
        !           197:    fflush(ofile);
        !           198:    }
        !           199: 
        !           200: /*
        !           201:  * gdpause(color) - pause for acknowledgement, showing color to hint at reason.
        !           202:  * Return last character before '\n', 0 if none, or EOF if not interactive.
        !           203:  */
        !           204: 
        !           205: gdpause(color)
        !           206: int color;
        !           207:    {
        !           208:    int c1, c2, pline;
        !           209: 
        !           210:    if (!ifile)
        !           211:       return EOF;
        !           212:    EndRun();
        !           213:    fputs("\r\007\033",ofile);          /* ring bell */
        !           214:    pline = Height - Height / yscale;
        !           215:    aedout("Qx",Width-PromptSize,pline);
        !           216:    aedout("sbbb",PromptSize,color,0);
        !           217:    fflush(ofile);
        !           218:    c1 = 0;
        !           219:    while ((c2 = getc(ifile)) != '\n')
        !           220:       if (c2 == EOF)  {
        !           221:          ifile = 0;
        !           222:          c1 = EOF;
        !           223:          break;
        !           224:          }
        !           225:       else
        !           226:          c1 = c2;
        !           227:    aedout("Qx",Width-PromptSize,pline);
        !           228:    aedout("sbbb",PromptSize,bgcolor,0);
        !           229:    return c1;
        !           230:    }
        !           231: 
        !           232: /*
        !           233:  * gdterm() - terminate graphics
        !           234:  */
        !           235: 
        !           236: gdterm()
        !           237:    {
        !           238:    if (!ofile)
        !           239:       return;                  /* if no file, just return */
        !           240:    EndRun();
        !           241:    aedout("Gs","3DNNN");       /* reset encoding */
        !           242:    aedout("\r");               /* exit graphics mode */
        !           243:    }
        !           244: 
        !           245: /*
        !           246:  * aedout(s,args) - output command to the AED.
        !           247:  *  s is a string specifying the command format a la printf.  The first
        !           248:  *  character (or two chars if first is '+') are the AED command.  Additional
        !           249:  *  characters specify formats for outputting additional arguments (see below).
        !           250:  */
        !           251: 
        !           252: /*VARARGS1*/
        !           253: static aedout (s, va_alist)
        !           254: char *s;
        !           255: va_dcl
        !           256:    {
        !           257:    va_list ap;
        !           258:    char c;
        !           259:    unsigned int n, x, y;
        !           260: 
        !           261:    va_start(ap);
        !           262:    if (putc(*s++,ofile) == '+')
        !           263:       putc(*s++,ofile);
        !           264:    while (c = *s++)
        !           265:       switch (c)  {            /* Output formats for add'l args:  */
        !           266:          case 'b':                     /* b - single byte unaltered */
        !           267:          case 'c':                     /* c - single char unaltered */
        !           268:             n = va_arg(ap,int);
        !           269:             putc(n, ofile);
        !           270:             break;
        !           271:          case 'i':                     /* i - 16-bit integer as two bytes */
        !           272:             n = va_arg(ap,int);
        !           273:             putc(n>>8, ofile);
        !           274:             putc(n, ofile);
        !           275:             break;
        !           276:          case 's':                     /* s - string terminated by '\0' */
        !           277:             fputs(va_arg(ap,int),ofile);
        !           278:             break;
        !           279:          case 'x':                     /* x - two args give x and y coords */
        !           280:             x = va_arg(ap,int);
        !           281:             y = va_arg(ap,int);
        !           282:             putc(((x>>4)&0xF0) | (y>>8), ofile);
        !           283:             putc(x, ofile);
        !           284:             putc(y, ofile);
        !           285:             break;
        !           286:          default:                      /* unrecognized - just echoed */
        !           287:             putc(c, ofile);
        !           288:          }
        !           289:    va_end(ap);
        !           290:    }
        !           291: 
        !           292: 
        !           293: /*
        !           294:  * memmon.c - memory monitoring code excluding the device driver.
        !           295:  *  When MemMon is undefined, gc.h defines these entrypoints
        !           296:  *  as null macros.
        !           297:  */
        !           298: 
        !           299: /*
        !           300:  * Color list, indexed by block type or defined symbol.
        !           301:  *  Every entry has 3 bits each (left to right) for red, green, blue.
        !           302:  *  White is used for blocks not expected in the block region.
        !           303:  */
        !           304: 
        !           305: static int clist[] = {
        !           306:                /*  --- these entries change color in marking phase ---  */
        !           307:     0777,      /*  0. T_Null     white    null value  */
        !           308:     0777,      /*  1. T_Integer  white    integer  */
        !           309:     0777,      /*  2. T_Longint  white    long integer  */
        !           310:     0007,      /*  3. T_Real     blue     real number  */
        !           311:     0540,      /*  4. T_Cset     brown    cset  */
        !           312:     0405,      /*  5. T_File     purple   file block  */
        !           313:     0777,      /*  6. T_Proc     white    procedure block  */
        !           314:     0060,      /*  7. T_List     green    list header block  */
        !           315:     0770,      /*  8. T_Table    yellow   table header block  */
        !           316:     0077,      /*  9. T_Record   cyan     record block  */
        !           317:     0773,      /* 10. T_Telem    lt yel   table element block  */
        !           318:     0272,      /* 11. T_Lelem    lt grn   list element block  */
        !           319:     0756,      /* 12. T_Tvsubs   pink     substring trapped variable  */
        !           320:     0777,      /* 13. T_Tvkywd   white    keyword trapped variable  */
        !           321:     0751,      /* 14. T_Tvtbl    orange   table elem trapped variable  */
        !           322:     0600,      /* 15. T_Set      red      set header block  */
        !           323:     0700,      /* 16. T_Selem    brt red  set element block  */
        !           324:     0004,      /* 17. T_Refresh  navy     refresh block  */
        !           325:     0777,      /* 18. T_Coexpr   white    co-expression block */
        !           326:     0777,      /* 19.            white    unused */
        !           327:     0777,      /* 20.            white    unused */
        !           328:     0777,      /* 21.            white    unused */
        !           329:     0777,      /* 22. UNcolr     white    unknown type  */
        !           330:     0776,      /* 23. STcolr     ivory    unbroken string  */
        !           331:     0344,      /* 24. STBcolr    blue     string separator  */
        !           332:                /*  --- these entries remain constant ---  */
        !           333:     0000,      /* 25. BGcolr     black    background  */
        !           334:     0222,      /* 26. AVcolr     med gry  available space  */
        !           335:     0000,      /* 27. BKBcolr    black    block border  */
        !           336:     0700,      /* 28. GCcolr     red      begin garbage collection */
        !           337:     0770,      /* 29. GARcolr    yellow   screen contents are garbage */
        !           338:     0007,      /* 30. VALcolr    blue     screen contents are valid data */
        !           339:     0070,      /* 31. GOcolr     green    ready to go after garb coll */
        !           340:                /*  --- these entries are used for color changes ---  */
        !           341:     0222,      /* 32. MKcolr     med gry  marked block  */
        !           342:     0000,      /* 33. UMcolr     black    unmarked block  */
        !           343:     0222,      /* 34. UMBcolr    med gry  unmarked block border  */
        !           344:     };
        !           345: 
        !           346: #define NColors 33     /* number of colors copied directly to color map */
        !           347: #define TColors 25     /* number of those which are transmutable */
        !           348: 
        !           349: #define UNcolr 22
        !           350: #define STcolr 23
        !           351: #define STBcolr 24
        !           352: #define BGcolr 25
        !           353: #define AVcolr 26
        !           354: #define BKBcolr 27
        !           355: #define GCcolr 28
        !           356: #define GARcolr 29
        !           357: #define VALcolr 30
        !           358: #define GOcolr 31
        !           359: #define MKcolr 32
        !           360: #define UMcolr 33
        !           361: #define UMBcolr 34
        !           362: 
        !           363: /*
        !           364:  * Color map buffer, initialized in MMInit and thereafter unaltered.
        !           365:  *  The color map downloaded to the display is always NColors+Bcolors
        !           366:  *  long and normally starts at cbuff+NColors.  After marking and before
        !           367:  *  compaction, marked blocks are shown in color by downloading a map
        !           368:  *  beginning at the front of cbuff.
        !           369:  */
        !           370: 
        !           371: int cbuff[3*NColors];
        !           372: 
        !           373: /*
        !           374:  * Miscellaney.
        !           375:  */
        !           376: 
        !           377: static char *mmdev;            /* name of monitoring device, if used */
        !           378: static int currcolor = UNcolr; /* current block output color */
        !           379: static int sstart;             /* origin of string space display */
        !           380: static int scale = 16;         /* initial scaling;  may decrease  */
        !           381: 
        !           382: #define NSkip 4                        /* empty lines between blocks and strings */
        !           383: #define Gran 4                 /* granularity of display (in bytes) */
        !           384: #define PaintBlk(addr,size,color,b)  \
        !           385:     gdpaint(((addr)-blkbase)/Gran,(size)/Gran,color,b)
        !           386: #define PaintStr(addr,size,color,b)  \
        !           387:     gdpaint(sstart+((addr)-strbase)/Gran,(size)/Gran,color,b)
        !           388: 
        !           389: /*
        !           390:  * MMInit() - initialization.
        !           391:  */
        !           392: 
        !           393: MMInit()
        !           394:    {
        !           395:    int i;
        !           396:    extern char *getenv();
        !           397: 
        !           398:    if (!(mmdev = getenv("MEMMON")))
        !           399:       return;
        !           400:    for (i=0; i<TColors; i++)  {
        !           401:       cbuff[i] = clist[UMcolr];
        !           402:       cbuff[i+NColors] = clist[i];
        !           403:       cbuff[i+2*NColors] = clist[MKcolr];
        !           404:       }
        !           405:    for (i=TColors; i<NColors; i++)
        !           406:       cbuff[i] = cbuff[i+NColors] = clist[i];
        !           407:    cbuff[BKBcolr] = clist[UMBcolr];
        !           408:    gdinit(mmdev);
        !           409:    }
        !           410: 
        !           411: /*
        !           412:  * MMType(t) - set type for subsequent block allocation.
        !           413:  */
        !           414: 
        !           415: MMType(t)
        !           416: int t;
        !           417:    {
        !           418:    currcolor = t;
        !           419:    }
        !           420: 
        !           421: /*
        !           422:  * MMAlc(n) - show allocation of n block bytes at blkfree.
        !           423:  */
        !           424: 
        !           425: MMAlc(n)
        !           426: int n;
        !           427:    {
        !           428:    if (!mmdev)
        !           429:       return;
        !           430:    if (!sstart)
        !           431:       refresh();
        !           432:    PaintBlk(blkfree,n,currcolor,BKBcolr);
        !           433:    gdflush();
        !           434:    currcolor = UNcolr;
        !           435:    }
        !           436: 
        !           437: /*
        !           438:  * MMStr(n) - show allocation of n string bytes at strfree.
        !           439:  *  Each pixel on the display represents multiple bytes.  A pixel in which any
        !           440:  *  string ends will be STBcolr;  pixels corresponding to nonterminal characters
        !           441:  *  of one string will be STcolr.  This method makes long strings individually
        !           442:  *  distinguishable from each other and from runs of short strings, and allows
        !           443:  *  continuous output with no backtracking as the string space is allocated.
        !           444:  */
        !           445: 
        !           446: MMStr(slen)
        !           447: int slen;
        !           448:    {
        !           449:    int s, e;
        !           450: 
        !           451:    if (!mmdev)
        !           452:       return;
        !           453:    if (!sstart)
        !           454:       refresh();
        !           455:    s = (strfree-strbase+Gran-1) / Gran;        /* start (first pixel wholly owned) */
        !           456:    e = (strfree-strbase+slen-1) / Gran;        /* end pixel */
        !           457:    if (e < s)                          /* if no new pixels, return */
        !           458:       return;
        !           459:    gdpaint(sstart+s,e-s+1,STcolr,STBcolr);
        !           460:    gdflush();
        !           461:    }
        !           462: 
        !           463: /*
        !           464:  * MMBGC() - begin garbage collection.
        !           465:  */
        !           466: 
        !           467: MMBGC()
        !           468:    {
        !           469:    if (!mmdev)
        !           470:       return;
        !           471:    gdpause(GCcolr);
        !           472:    }
        !           473: 
        !           474: /*
        !           475:  * MMMark(block,type) - mark indicated block during garbage collection.
        !           476:  */
        !           477: 
        !           478: MMMark(block,type)
        !           479: char *block;
        !           480: int type;
        !           481:    {
        !           482:    if (mmdev)
        !           483:       PaintBlk(block,BlkSize(block),NColors+type,BKBcolr);
        !           484:    }
        !           485: 
        !           486: /*
        !           487:  * MMSMark - Mark String.
        !           488:  */
        !           489: 
        !           490: MMSMark(saddr,slen)
        !           491: char *saddr;
        !           492: int slen;
        !           493:    {
        !           494:    int s, e;
        !           495: 
        !           496:    if (!mmdev)
        !           497:       return;
        !           498:    s = (saddr-strbase+Gran-1) / Gran;  /* start (first pixel wholly owned) */
        !           499:    e = (saddr-strbase+slen-1) / Gran;  /* end pixel */
        !           500:    if (e >= s)                         /* if anything to paint... */
        !           501:       gdpaint(sstart+s,e-s+1,NColors+STcolr,NColors+STBcolr);
        !           502:    }
        !           503: 
        !           504: /*
        !           505:  * MMEGC() - end garbage collection.
        !           506:  */
        !           507: 
        !           508: MMEGC()
        !           509:    {
        !           510:    if (!mmdev)
        !           511:       return;
        !           512:    if (gdpause(GARcolr) != EOF)
        !           513:        gdmap(cbuff,NColors+TColors);
        !           514:    while (gdpause(VALcolr) == '-')  {
        !           515:        gdmap(cbuff+NColors,NColors+TColors);
        !           516:        gdpause(GARcolr);
        !           517:        gdmap(cbuff,NColors+TColors);
        !           518:        }
        !           519:    refresh();
        !           520:    gdpause(GOcolr);
        !           521:    }
        !           522: 
        !           523: /*
        !           524:  * MMTerm() - terminate memory monitoring.
        !           525:  */
        !           526: 
        !           527: MMTerm()
        !           528:    {
        !           529:    if (mmdev)
        !           530:       gdterm();
        !           531:    }
        !           532: 
        !           533: /*
        !           534:  * refresh() - redraw screen, initially or after garbage collection.
        !           535:  */
        !           536: 
        !           537: static refresh()
        !           538:    {
        !           539:    char *p;
        !           540:    int n;
        !           541: 
        !           542:    if (layout())
        !           543:       gdflood(BGcolr);
        !           544:    else
        !           545:       PaintBlk(blkbase,blkfree-blkbase,AVcolr,-1);
        !           546:    PaintStr(strfree,strend-strfree,AVcolr,-1);
        !           547:    PaintBlk(blkfree,maxblk-blkfree,AVcolr,-1);
        !           548:    gdmap(cbuff+NColors,NColors+TColors);
        !           549:    PaintStr(strbase,strfree-strbase,STcolr,BKBcolr);
        !           550:    for (p = blkbase; p < blkfree; p += n)
        !           551:       PaintBlk(p,n=BlkSize(p),BlkType(p),BKBcolr);
        !           552:    }
        !           553: 
        !           554: /*
        !           555:  * layout - determine screen layout.  Return NZ iff different from previous.
        !           556:  */
        !           557: 
        !           558: static layout()
        !           559: {
        !           560:    int hpixels, spixels, avail, mid, width, ideal, diff;
        !           561:    static int oldscale, oldss;
        !           562: 
        !           563:    hpixels = (maxblk - blkbase) / Gran + 1;
        !           564:    spixels = (strend - strbase) / Gran + 1;
        !           565:    while (scale > 1 && (hpixels + spixels > gdsize(scale)))
        !           566:       --scale;
        !           567:    gdscale(scale);
        !           568:    avail = gdsize(scale); 
        !           569:    width = gdwidth();
        !           570:    mid = avail / 2;
        !           571:    mid -= mid % width;
        !           572:    ideal = ((hpixels + width - 1) / width + NSkip) * width;   
        !           573:    if (ideal <= mid && spixels <= avail - mid)
        !           574:       sstart = mid;
        !           575:    else if (ideal + spixels <= avail)
        !           576:       sstart = ideal;
        !           577:    else if (hpixels + spixels <= avail)
        !           578:       sstart = avail - spixels;
        !           579:    else
        !           580:       sstart = hpixels + 1;
        !           581:    diff = (scale != oldscale) || (sstart != oldss); 
        !           582:    oldscale = scale;
        !           583:    oldss = sstart;
        !           584:    return diff;
        !           585:    }
        !           586: 
        !           587: #else MemMon
        !           588: static int x;          /* prevent null module when MemMon not defined */
        !           589: #endif MemMon

unix.superglobalmegacorp.com

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