Annotation of researchv9/X11/src/X.V11R1/lib/oldXtk/Boolean.c, revision 1.1.1.1

1.1       root        1: /* $Header: Boolean.c,v 1.2 87/09/12 12:41:35 swick Exp $ */
                      2: #ifndef lint
                      3: static char *sccsid = "@(#)Boolean.c   1.8     2/24/87";
                      4: #endif lint
                      5: 
                      6: /*
                      7:  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
                      8:  * 
                      9:  *                         All Rights Reserved
                     10:  * 
                     11:  * Permission to use, copy, modify, and distribute this software and its 
                     12:  * documentation for any purpose and without fee is hereby granted, 
                     13:  * provided that the above copyright notice appear in all copies and that
                     14:  * both that copyright notice and this permission notice appear in 
                     15:  * supporting documentation, and that the name of Digital Equipment
                     16:  * Corporation not be used in advertising or publicity pertaining to
                     17:  * distribution of the software without specific, written prior permission.  
                     18:  * 
                     19:  * 
                     20:  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
                     21:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
                     22:  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
                     23:  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
                     24:  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
                     25:  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
                     26:  * SOFTWARE.
                     27:  */
                     28: 
                     29: 
                     30: #include <stdio.h>
                     31: #include <strings.h>
                     32: #include "Xlib.h"
                     33: #include "Intrinsic.h"
                     34: #include "Boolean.h"
                     35: #include "Atoms.h"
                     36: 
                     37: /* Private Definitions */
                     38: 
                     39: typedef void (*NotifyProc)();
                     40: 
                     41: typedef struct _WidgetDataRec {
                     42:     Display    *dpy;           /* widget display connection */
                     43:     Window     window;         /* widget window */
                     44:     Position   x, y;           /* location of widget */
                     45:     Dimension  borderWidth;    /* border width in pixels */
                     46:     Dimension   width, height; /* width/height in pixels */
                     47:     int                ibw, ibh;       /* internal border width/height in pixels */
                     48:     char       *text;          /* button text */
                     49:     int                fgpixel;        /* color index for text */
                     50:     int                bgpixel;        /* color index for background */
                     51:     int                brpixel;        /* color for border */
                     52:     Boolean    highlighted;    /* are we highlighted? */
                     53:     Boolean    value;          /* pointer to value */
                     54:     XFontStruct        *fontstruct;    /* font for text */
                     55:     Dimension  twidth, theight;/* text width/height */
                     56:     XtJustify  justify;                /* text justification */
                     57:     NotifyProc proc;           /* procedure to invoke on value change */
                     58:     caddr_t    tag;            /* widget client data */
                     59:     XtEventsPtr eventTable;    /* Table for Translation Manager */
                     60:     caddr_t    state;          /* state for Translation Manager */
                     61:     int                eventlevels;    /* recursion levels of event handling */
                     62:     GC         gc;             /* current gc */
                     63:     GC         onGC;           /* GC to use when on */
                     64:     GC         offGC;          /* GC to use when off */
                     65: } WidgetDataRec, *WidgetData;
                     66: 
                     67: extern void Dummy(); 
                     68: static WidgetDataRec globaldata;
                     69: static WidgetDataRec globalinit = {
                     70: 
                     71:     NULL,              /* Display dpy; */
                     72:     NULL,              /* Window window; */
                     73:     0,0,               /* x,y */
                     74:     1,                 /* int borderWidth; */
                     75:     0, 0,              /* int width, height; */
                     76:     4, 2,              /* int ibw, ibh; */
                     77:     NULL,              /* char *text; */
                     78:     NULL,              /* int fgpixel; */ /* init proc */
                     79:     NULL,              /* int bgpixel; */ /* init proc */
                     80:     NULL,              /* Pixmap brpixmap; */ /* init proc */
                     81:     FALSE,             /* Boolean highlighted; */
                     82:     FALSE,     /* Boolean value; */
                     83:     NULL,              /* XFontStruct *fontstruct; */ /* init proc */
                     84:     0, 0,              /* int twidth, theight; */
                     85:     XtjustifyCenter,   /* justify */
                     86:     Dummy,             /* void (*proc) (); */
                     87:     NULL,              /* caddr_t tag; */
                     88:     NULL,              /* event table pointer */
                     89:     NULL,              /* state for Translation Manager */
                     90:     NULL,              /* event levels */
                     91:     NULL,              /* gc */
                     92:     NULL,              /* onGC */
                     93:     NULL,              /* offGC */
                     94: };
                     95: 
                     96: /* Private Data */
                     97: 
                     98: static int defaultBorderWidth          = 1;
                     99: static int defaultInternalBorderWidth  = 4;
                    100: static int defaultInternalBorderHeight         = 2;
                    101: static XtJustify defaultJustify        = XtjustifyCenter;
                    102: static NotifyProc defaultFunction      = Dummy;
                    103: 
                    104: static Resource resources[] = {
                    105:     {XtNvalue,         XtCValue,       XrmRBoolean,    sizeof(Boolean),
                    106:         (caddr_t)&globaldata.value,    (caddr_t)NULL},
                    107:     {XtNwindow,                XtCWindow,      XrmRWindow,     sizeof(Window), 
                    108:        (caddr_t)&globaldata.window,    (caddr_t)NULL},
                    109:     {XtNborderWidth,   XtCBorderWidth, XrmRInt,                sizeof(int), 
                    110:        (caddr_t)&globaldata.borderWidth, (caddr_t)&defaultBorderWidth},
                    111:     {XtNwidth,         XtCWidth,       XrmRInt,                sizeof(int), 
                    112:        (caddr_t)&globaldata.width,     (caddr_t)NULL},
                    113:     {XtNheight,                XtCHeight,      XrmRInt,                sizeof(int), 
                    114:        (caddr_t)&globaldata.height,    (caddr_t)NULL},
                    115:     {XtNinternalWidth, XtCWidth,       XrmRInt,                sizeof(int), 
                    116:        (caddr_t)&globaldata.ibw,       (caddr_t)&defaultInternalBorderWidth},
                    117:     {XtNinternalHeight,        XtCHeight,      XrmRInt,                sizeof(int), 
                    118:        (caddr_t)&globaldata.ibh,       (caddr_t)&defaultInternalBorderHeight},
                    119:     {XtNlabel,         XtCLabel,       XrmRString,     sizeof(char *), 
                    120:        (caddr_t)&globaldata.text,      (caddr_t)NULL},
                    121:     {XtNforeground,    XtCColor,       XrmRPixel,      sizeof(int), 
                    122:        (caddr_t)&globaldata.fgpixel,   (caddr_t)&XtDefaultFGPixel},
                    123:     {XtNbackground,    XtCColor,       XrmRPixel,      sizeof(int), 
                    124:        (caddr_t)&globaldata.bgpixel,   (caddr_t)&XtDefaultBGPixel},
                    125:     {XtNborder,                XtCColor,       XrmRPixel,      sizeof(int),
                    126:        (caddr_t)&globaldata.brpixel,   (caddr_t)&XtDefaultFGPixel},
                    127:     {XtNfont,          XtCFont,        XrmRFontStruct, sizeof(XFontStruct *),
                    128:        (caddr_t)&globaldata.fontstruct,(caddr_t)NULL},
                    129:     {XtNjustify,       XtCJustify,     XtRJustify,     sizeof(XtJustify), 
                    130:         (caddr_t)&globaldata.justify,  (caddr_t)&defaultJustify},
                    131:     {XtNfunction,      XtCFunction,    XtRFunction,    sizeof(NotifyProc), 
                    132:        (caddr_t)&globaldata.proc,      (caddr_t)&defaultFunction},
                    133:     {XtNparameter,     XtCParameter,   XrmRPointer,    sizeof(caddr_t), 
                    134:        (caddr_t)&globaldata.tag,       (caddr_t)NULL},
                    135:     {XtNeventBindings, XtCEventBindings,XtREventBindings, sizeof(caddr_t), 
                    136:        (caddr_t)&globaldata.eventTable,NULL },
                    137: };
                    138: 
                    139: static char *defaultEventBindings[] = {
                    140:        "<EnterWindow>:         highlight\n",
                    141:        "<LeaveWindow>:         unhighlight\n",
                    142:        "<ButtonPress>left:     toggle\n",
                    143:        "<ButtonRelease>left:   notify\n",
                    144:        NULL
                    145: };
                    146: 
                    147: /****************************************************************
                    148:  *
                    149:  * Private Procedures
                    150:  *
                    151:  ****************************************************************/
                    152: 
                    153: static Boolean initialized = FALSE; /* !!! STATIC !!! */
                    154: 
                    155: static XContext widgetContext;
                    156: 
                    157: static void BooleanInitialize (dpy)
                    158:  Display *dpy;
                    159: {
                    160:     if (initialized)
                    161:        return;
                    162:     initialized = TRUE;
                    163: 
                    164:     widgetContext = XUniqueContext();
                    165: 
                    166:     globalinit.fontstruct = XLoadQueryFont(dpy,"fixed");
                    167:     globalinit.justify = XtjustifyCenter;
                    168:     globalinit.eventTable = XtParseEventBindings(defaultEventBindings);
                    169: }
                    170: 
                    171: static void SetTextWidthAndHeight(data)
                    172: WidgetData data;
                    173: {
                    174:        data->theight = data->fontstruct->max_bounds.ascent +
                    175:                data->fontstruct->max_bounds.descent;
                    176:        data->twidth = XTextWidth(data->fontstruct, data->text,
                    177:                                  strlen(data->text));
                    178: }
                    179: 
                    180: /*ARGSUSED*/
                    181: static void Dummy(p)
                    182: caddr_t p;
                    183: {
                    184:     (void) printf("dummy notify for Boolean\n");
                    185: }
                    186: 
                    187: static void Ignore ()
                    188: {
                    189:    (void) printf("you are being ignored\n");
                    190: }
                    191: 
                    192: /*
                    193:  * Given a display and window, get the widget data.
                    194:  */
                    195: 
                    196: static WidgetData DataFromWindow(dpy, window)
                    197: Display *dpy;
                    198: Window window;
                    199: {
                    200:     WidgetData result;
                    201:     if (XFindContext(dpy, window, widgetContext, (caddr_t *)&result))
                    202:        return NULL;
                    203:     return result;
                    204: }
                    205: 
                    206: /*
                    207:  *
                    208:  * Repaint the widget window
                    209:  *
                    210:  */
                    211: 
                    212: static void Redisplay (data)
                    213: WidgetData     data;
                    214: {
                    215:     int     textx, texty;
                    216:     Window  w = data->window;
                    217: 
                    218: 
                    219:     /*
                    220:      * Calculate Text x,y given window width and text width
                    221:      * to the specified justification
                    222:      */
                    223: 
                    224:     if (data->justify == XtjustifyLeft) 
                    225:        textx = 2;
                    226:     else if (data->justify == XtjustifyRight)
                    227:        textx = data->width - data->twidth;
                    228:     else
                    229:         textx = ((data->width - data->twidth) / 2);
                    230:     if (textx < 0) textx = 0;
                    231:     texty = (data->height - data->theight) / 2 +
                    232:        data->fontstruct->max_bounds.ascent;
                    233: 
                    234:     XFillRectangle(data->dpy, w,
                    235:        (data->highlighted ? data->onGC : data->offGC),
                    236:        0, 0, data->width, data->height);
                    237: 
                    238:     XDrawImageString(
                    239:        data->dpy, w, (((data->value)) ? data->offGC : data->onGC),
                    240:        textx, texty, data->text, strlen(data->text));
                    241: 
                    242: }
                    243: 
                    244: extern void Destroy();
                    245: 
                    246: /*
                    247:  *
                    248:  * Generic widget event handler
                    249:  *
                    250:  */
                    251: 
                    252: static XtEventReturnCode EventHandler(event, eventdata)
                    253: XEvent *event;
                    254: caddr_t eventdata;
                    255: {
                    256:     WidgetData         data = (WidgetData) eventdata;
                    257:     XtActionTokenPtr   actionList;
                    258:     NotifyProc         proc;
                    259: 
                    260:   data->eventlevels++;
                    261: 
                    262:     switch (event->type) {
                    263:        case ConfigureNotify:
                    264:            data->width = event->xconfigure.width;
                    265:            data->height = event->xconfigure.height;
                    266:            data->borderWidth = event->xconfigure.border_width;
                    267:            break;
                    268: 
                    269:         case DestroyNotify: Destroy(data); break;
                    270: 
                    271:         case Expose:
                    272:            if (event->xexpose.count == 0)
                    273:                Redisplay(data);
                    274:            break;
                    275: 
                    276:        default:
                    277:            actionList = (XtActionTokenPtr)XtTranslateEvent(
                    278:                event, (TranslationPtr) data->state);
                    279:            for (; actionList != NULL; actionList = actionList->next) {
                    280:                if (actionList->type == XttokenAction) {
                    281:                    proc = (NotifyProc)XtInterpretAction(
                    282:                         data->dpy, 
                    283:                        (TranslationPtr) data->state,
                    284:                        actionList->value.action);
                    285:                    (*proc) (data);
                    286:                }
                    287:            }
                    288:            break;
                    289:     }
                    290: 
                    291:     data->eventlevels--;
                    292:     return (XteventHandled);
                    293: }
                    294: 
                    295: /*
                    296:  *
                    297:  * Widget hilight event handler
                    298:  *
                    299:  */
                    300: 
                    301: /*ARGSUSED*/
                    302: static XtEventReturnCode Highlight(data)
                    303:     WidgetData data;
                    304: {
                    305:     data->highlighted = TRUE;
                    306:     Redisplay(data);
                    307:     return (XteventHandled);
                    308: }
                    309: 
                    310: /*
                    311:  *
                    312:  * Widget un-hilight event handler
                    313:  *
                    314:  */
                    315: 
                    316: /*ARGSUSED*/
                    317: static XtEventReturnCode Unhighlight(data)
                    318:     WidgetData data;
                    319: {
                    320:     data->highlighted = FALSE;
                    321:     Redisplay(data);
                    322:     return (XteventHandled);
                    323: }
                    324: 
                    325: static void SetValue(data, newval)
                    326:     WidgetData data;
                    327:     Boolean    newval;
                    328: {
                    329:     if ((data->value) == newval) return;
                    330: 
                    331:     (data->value) = newval;
                    332:     data->gc = (newval ? data->onGC : data->offGC);
                    333: /*
                    334:     XSetWindowBackground(data->dpy, data->window, data->gc->value.background);
                    335: */
                    336:     Redisplay(data);
                    337: }
                    338: 
                    339: /*
                    340:  *
                    341:  * Widget set value event handler
                    342:  *
                    343:  */
                    344: 
                    345: /*ARGSUSED*/
                    346: static XtEventReturnCode On(event, eventdata)
                    347: XEvent *event;
                    348: caddr_t eventdata;
                    349: {
                    350:     WidgetData data = (WidgetData) eventdata;
                    351: 
                    352:     SetValue(data, TRUE);
                    353:     return (XteventHandled);
                    354: }
                    355: 
                    356: /*
                    357:  *
                    358:  * Widget un-set value event handler
                    359:  *
                    360:  */
                    361: 
                    362: /*ARGSUSED*/
                    363: static XtEventReturnCode Off(event, eventdata)
                    364: XEvent *event;
                    365: caddr_t eventdata;
                    366: {
                    367:     WidgetData data = (WidgetData) eventdata;
                    368: 
                    369:     SetValue(data, FALSE);
                    370:     return (XteventHandled);
                    371: }
                    372: 
                    373: /*
                    374:  *
                    375:  * Widget toggle value event handler
                    376:  *
                    377:  */
                    378: 
                    379: /*ARGSUSED*/
                    380: static XtEventReturnCode Toggle(data)
                    381:     WidgetData data;
                    382: {
                    383:     SetValue(data, ! (data->value));
                    384:     return (XteventHandled);
                    385: }
                    386: 
                    387: /*
                    388:  * Widget handler to invoke application routine */
                    389: 
                    390: /*ARGSUSED*/
                    391: static XtEventReturnCode Notify(data)
                    392:     WidgetData data;
                    393: {
                    394:        Redisplay(data);
                    395:        XFlush(data->dpy);
                    396:        data->proc(data->tag); /* invoke application proc */
                    397:        
                    398:        return(XteventHandled);
                    399: }
                    400: 
                    401: 
                    402: /*
                    403:  *
                    404:  * Destroy the widget
                    405:  *
                    406:  */
                    407: 
                    408: static void Destroy(data)
                    409: WidgetData     data;
                    410: {
                    411:     (void) XDeleteContext(data->dpy, data->window, widgetContext);
                    412:     XtClearEventHandlers(data->dpy, data->window);
                    413:     XtFree ((char*)data->text);
                    414:     XtFree ((char *) data);
                    415: }
                    416: 
                    417: /****************************************************************
                    418:  *
                    419:  * Public Procedures
                    420:  *
                    421:  ****************************************************************/
                    422: 
                    423: Window XtBooleanCreate(dpy, parent, args, argCount)
                    424:     Display  *dpy;
                    425:     Window   parent;
                    426:     ArgList  args;
                    427:     int      argCount;
                    428: {
                    429:     WidgetData data;
                    430:     XrmNameList        names;
                    431:     XrmClassList classes;
                    432:     Position x, y;
                    433:     unsigned int depth;
                    434:     Drawable   root;
                    435:     unsigned long valuemask;
                    436:     XSetWindowAttributes wvals;
                    437:     XGCValues values;
                    438: 
                    439:     static XtActionsRec actionsTable[] = {
                    440:        {"toggle",      (caddr_t)Toggle},
                    441:        {"highlight",   (caddr_t)Highlight},
                    442:        {"unhighlight", (caddr_t)Unhighlight},
                    443:        {"notify",      (caddr_t)Notify},
                    444:        {"on",          (caddr_t)On},
                    445:        {"off",         (caddr_t)Off},
                    446:        {NULL, NULL}
                    447:     };
                    448: 
                    449: 
                    450:    if (!initialized)
                    451:        BooleanInitialize(dpy);
                    452: 
                    453:    data = (WidgetData) XtMalloc (sizeof(WidgetDataRec));
                    454: 
                    455:     /* Set Default Values */
                    456:     globaldata = globalinit;
                    457:     globaldata.dpy = dpy;
                    458:     XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent,
                    459:         "boolean", "Boolean", &names, &classes);
                    460:     *data = globaldata;
                    461: 
                    462:     data->state = XtSetActionBindings(
                    463:         data->dpy,
                    464:        data->eventTable, actionsTable, (caddr_t)Ignore);
                    465: 
                    466:     if (data->text == NULL)
                    467:        data->text = XrmNameToAtom(names[XrmNameListLength(names) - 1]);
                    468:     data->text = strcpy( XtMalloc ((unsigned) strlen(data->text) + 1),
                    469:                         data->text);
                    470: 
                    471:     /* obtain text dimensions and calculate the window size */
                    472:     SetTextWidthAndHeight(data);
                    473:     if (data->width == 0) data->width = data->twidth + 2*data->ibw;
                    474:     if (data->height == 0) data->height = data->theight + 2*data->ibh;
                    475: 
                    476:     wvals.background_pixel = data->bgpixel;
                    477:     wvals.border_pixel = data->brpixel;
                    478:     wvals.bit_gravity = CenterGravity;
                    479:     
                    480:     valuemask = CWBackPixel | CWBorderPixel | CWBitGravity;
                    481:     
                    482:     if (data->window != NULL) {
                    483:        /* set global data from window parameters */
                    484:        if (
                    485:            XGetGeometry(
                    486:                data->dpy, data->window, &root,
                    487:                &x, &y, &(data->width), &(data->height),
                    488:                &(data->borderWidth), &depth)
                    489:            ) {
                    490:            XReparentWindow(data->dpy, data->window, parent, data->x,data->y);
                    491:            XChangeWindowAttributes(data->dpy, data->window, valuemask, &wvals);
                    492:        } else
                    493:            data->window = NULL;
                    494:     }
                    495:     if (data->window == NULL)
                    496:        data->window = XCreateWindow(data->dpy, parent, data->x, data->y,
                    497:                         data->width, data->height, data->borderWidth,
                    498:                         0, (unsigned) InputOutput, (Visual *) CopyFromParent,
                    499:                         valuemask, &wvals);
                    500: 
                    501:     values.foreground = data->fgpixel;
                    502:     values.background = data->bgpixel;
                    503:     values.font = data->fontstruct->fid;
                    504:     valuemask = GCForeground | GCBackground | GCFont;
                    505:     data->onGC = XtGetGC(data->dpy, widgetContext, data->window,
                    506:                         valuemask, &values);
                    507:     values.foreground = data->bgpixel;
                    508:     values.background = data->fgpixel;
                    509:     data->offGC = XtGetGC(data->dpy, widgetContext, data->window,
                    510:                          valuemask, &values);
                    511: 
                    512:     XtSetNameAndClass(data->dpy, data->window, names, classes);
                    513:     XrmFreeNameList(names);
                    514:     XrmFreeClassList(classes);
                    515: 
                    516:     (void)XSaveContext(data->dpy, data->window, widgetContext, (caddr_t)data);
                    517: 
                    518:     /* set handler for expose, resize, and message events */
                    519:     XtSetEventHandler (data->dpy, data->window, (XtEventHandler) EventHandler,
                    520:      StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask
                    521:      | EnterWindowMask | LeaveWindowMask, (caddr_t)data);
                    522: 
                    523:     return (data->window);
                    524: }
                    525: 
                    526: /*
                    527:  * Set specified arguments in widget
                    528:  */
                    529: 
                    530: void XtBooleanSetValues (dpy, window, args, argCount)
                    531:     Display    *dpy;
                    532:     Window     window;
                    533:     ArgList    args;
                    534:     int                argCount;
                    535: {
                    536:     WidgetData data;
                    537:     data = DataFromWindow(dpy, window);
                    538:     if (data == NULL) return;
                    539: 
                    540:     globaldata = *data;
                    541:     XtSetValues(resources, XtNumber(resources), args, argCount);
                    542: 
                    543:     (globaldata.value) = ((globaldata.value) ? TRUE : FALSE);
                    544: 
                    545:     if (strcmp (data->text, globaldata.text)
                    546:          || data->fontstruct != globaldata.fontstruct) {
                    547:        XtGeometryReturnCode reply;
                    548:        WindowBox reqbox, replybox;
                    549: 
                    550:        globaldata.text = strcpy(
                    551:            XtMalloc ((unsigned) strlen(globaldata.text) + 1),
                    552:            globaldata.text);
                    553:         XtFree ((char *) data->text);
                    554: 
                    555:        /* obtain text dimensions and calculate the window size */
                    556:        SetTextWidthAndHeight(&globaldata);
                    557:        reqbox.width = (int) globaldata.twidth + 2*globaldata.ibw;
                    558:        reqbox.height = (int) globaldata.theight + 2*globaldata.ibh;
                    559:        reply = XtMakeGeometryRequest(
                    560:                globaldata.dpy, globaldata.window,
                    561:                XtgeometryResize, &reqbox, &replybox);
                    562:        if (reply == XtgeometryAlmost) {
                    563:            reqbox = replybox;
                    564:            (void) XtMakeGeometryRequest(
                    565:                globaldata.dpy, globaldata.window,
                    566:                XtgeometryResize, &reqbox, &replybox);
                    567:        }
                    568:     }
                    569: 
                    570:     *data = globaldata;
                    571:     Redisplay (data);
                    572: }
                    573: 
                    574: /*
                    575:  * Get specified arguments from widget
                    576:  */
                    577: 
                    578: void XtBooleanGetValues (dpy, window, args, argCount)
                    579:     Display    *dpy;
                    580:     Window     window;
                    581:     ArgList    args;
                    582:     int                argCount;
                    583: {
                    584:     WidgetData data;
                    585:     data = DataFromWindow(dpy, window);
                    586:     if (data == NULL) return;
                    587: 
                    588:     globaldata = *data;
                    589:     XtGetValues(resources, XtNumber(resources), args, argCount);
                    590: }
                    591: 

unix.superglobalmegacorp.com

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