[comp.sources.amiga] v89i201: frag - show disk & file fragementation

page%swap@Sun.COM (Bob Page) (11/13/89)

Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
Posting-number: Volume 89, Issue 201
Archive-name: dos/fs/frag.1

Here are two utilities, "blocks" and "free",  to show disk and file
fragmentation.

[uuencoded executables included.  ..bob]

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	lmkfile
#	free.c
#	free.doc
#	free.hdr
#	free.uu
#	blocks.c
#	blocks.doc
#	blocks.uu
# This is archive 1 of a 1-part kit.
# This archive created: Sun Nov 12 17:42:24 1989
echo "extracting lmkfile"
sed 's/^X//' << \SHAR_EOF > lmkfile
Xall: blocks free
X
Xblocks: blocks.c
X    lc -v -O blocks
X    @blink from lib:cback.o blocks.o to blocks lib lib:lc.lib batch nodebug def
Xine __main=__tinymain verbose sc sd
X
Xfree: free.c
X    lc -cf -v -rr -O free
X    @blink from lib:cback.o free.o to free lib lib:lcr.lib batch nodebug define
X @_main=@_tinymain verbose sc sd
X
SHAR_EOF
echo "extracting free.c"
sed 's/^X//' << \SHAR_EOF > free.c
X#include <exec/types.h>
X#include <exec/io.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <libraries/filehandler.h>
X#include <intuition/intuition.h>
X#include <workbench/startup.h>
X#include <devices/trackdisk.h>
X
X#include <proto/exec.h>
X#include <proto/dos.h>
X#include <proto/graphics.h>
X#include <proto/intuition.h>
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
X#define error(s) { if (cli) Write(_Backstdout, (s), strlen(s)); }
X
X/* border sizes, shouldn't be hard coded ... */
X#define XLEFT 2
X#define XRIGHT 2
X#define YTOP 10
X#define YBOTTOM 1
X/* Max/Min window size */
X#define MAXHEIGHT (200 - YTOP - YBOTTOM)
X#define MAXWIDTH   (640 - XLEFT - XRIGHT)
X#define MINWIDTH 200
X#define MINHEIGHT 80
X
X/* Detach info */
Xlong _stack = 2000;
Xchar *_procname = "freeblks";
Xlong _priority = 0;
Xlong _BackGroundIO = TRUE;
Xextern long _Backstdout;
X
Xtypedef struct FileInfoBlock FIB;
Xtypedef struct InfoData INFO;
X
Xextern struct IntuitionBase *IntuitionBase;
Xextern struct GfxBase *GfxBase;
X
X/* Device access */
Xstruct MsgPort *port;
Xstruct IOStdReq *io;
Xint DevOpen;
X/* Partition characteristics */
Xlong blk_size, blk_offset, root_blk, *secbuf, *secbuf2;
Xstruct Window *win;
X/* size of window, of each block, etc */
Xint xdiv, rectw, recth, width, height;
Xint cli;
X
Xstruct NewWindow newwin = {
X    0, 0,
X    0, 0,
X    -1, -1,
X    CLOSEWINDOW,
X    WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | NOCAREREFRESH | RM
XBTRAP,
X    NULL,
X    NULL,
X    NULL,
X    NULL,
X    NULL,
X    0, 0, 0, 0,
X    WBENCHSCREEN
X};
X
X/* bcpl string -> C string */
Xchar *btoc_str(char *to, BSTR from)
X{
X    char *cstr = (char *)BADDR(from);
X
X    strncpy(to, cstr + 1, *cstr);
X    to[*cstr] = '\0';
X
X    return to;
X}
X
X/* Calculate coords on window for block 'block' on disk */
Xvoid cvt_point(long *x, long *y, long block)
X{
X    *x = rectw * (block / (xdiv * height)) + XLEFT;
X    *y = recth * (block % height) + YTOP;
X}
X
X/* Calc size, & open window */
Xint prepare_window(struct DeviceNode *dev)
X{
X    struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S
Xtartup);
X    ULONG *env = (ULONG *)BADDR(msg->fssm_Environ);
X    long blkscyl = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
X    long numcyls = env[DE_UPPERCYL] - env[DE_LOWCYL] + 1;
X    long blks;
X    static char title[80];
X
X    if (blkscyl <= MAXHEIGHT) /* Do a "nice" presentation, 1 cylinder per vert
Xline */
X    {
X        height = blkscyl;
X        xdiv = (numcyls / MAXWIDTH + 1); /* Nb of cylinders per vertical line *
X/
X        width = numcyls / xdiv;
X    }
X    else /* Just squash em in */
X    {
X        blks = numcyls * blkscyl;
X        height = MAXHEIGHT;
X        xdiv = (blks / MAXHEIGHT + 1) / MAXWIDTH + 1;
X        width = (blks / MAXHEIGHT + 1) / xdiv;
X    }
X    /* Size of rect for 1 block */
X    rectw = MINWIDTH / width + 1;
X    recth = MINHEIGHT / height + 1;
X
X    /* Open window */
X    btoc_str(title, dev->dn_Name);
X    strcat(title, ":, free blocks");
X    newwin.Title = title;
X    newwin.Width = rectw * width + XLEFT + XRIGHT;
X    newwin.Height = recth * height + YTOP + YBOTTOM;
X
X    if (win = OpenWindow(&newwin))
X    {
X        SetAPen(win->RPort, 2);
X        RectFill(win->RPort, XLEFT, YTOP, win->Width - XRIGHT - 1, win->Height
X- YBOTTOM - 1);
X        SetAPen(win->RPort, 3);
X        return TRUE;
X    }
X    return FALSE;
X}
X
X/* Reads sector at offset 'sector' from disk ('sector' must be a multiple of 51
X2) */
XBYTE *ReadSector(long sector, BYTE *buf, long len)
X{
X    io->io_Command = CMD_READ;
X    io->io_Length = len;
X    io->io_Data = (APTR)buf;
X    io->io_Offset = sector;
X    DoIO((struct IORequest *)io);
X    return (io->io_Error == 0) ? buf : NULL;
X}
X
X/* Turn motor on/off */
Xvoid Motor(int on)
X{
X    io->io_Command = TD_MOTOR;
X    io->io_Length = on;
X    DoIO((struct IORequest *)io);
X}
X
X/* Find device by name */
Xstruct DeviceNode *FindDevice(char *name)
X{
X    struct DeviceNode *devlist;
X    int l = strlen(name), l2;
X    char *name2;
X
X    Forbid();
X    devlist = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct Root
XNode *)(DOSBase->dl_Root))->rn_Info))->di_DevInfo);
X    for (;devlist; devlist = (struct DeviceNode *)BADDR(devlist->dn_Next))
X        if (devlist->dn_Type == DLT_DEVICE)
X        {
X            name2 = (char *)BADDR(devlist->dn_Name);
X            l2 = *name2;
X            if (l == l2 && strnicmp(name, name2 + 1, l) == 0) break;
X        }
X
X    Permit();
X    return devlist;
X}
X
X/* Find device by task */
Xstruct DeviceNode *TaskDevice(struct MsgPort *task)
X{
X    struct DeviceNode *devlist;
X
X    Forbid();
X    devlist = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct Root
XNode *)(DOSBase->dl_Root))->rn_Info))->di_DevInfo);
X    for (;devlist; devlist = (struct DeviceNode *)BADDR(devlist->dn_Next))
X        if (devlist->dn_Type == DLT_DEVICE)
X        {
X            if (task == devlist->dn_Task) { Permit(); return devlist; }
X        }
X
X    Permit();
X    return NULL;
X}
X
X/* Reads block n of *partition* */
XBYTE *ReadBlock(long *buf, long n)
X{
X    return(ReadSector((blk_offset + n) * blk_size * 4, (BYTE *)buf, blk_size *
X4));
X}
X
X/* Get partition characteristics, open device */
Xint setup(struct DeviceNode *dev)
X{
X    char devname[32];
X    struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S
Xtartup);
X    ULONG *env = (ULONG *)BADDR(msg->fssm_Environ);
X    long err;
X
X    port = CreatePort(0, 0);
X    if (!port)
X    {
X        error("No port!\n");
X        return FALSE;
X    }
X    io = CreateStdIO(port);
X    if (!io)
X    {
X        error("No IO request!\n");
X        return FALSE;
X    }
X    err = OpenDevice(btoc_str(devname, msg->fssm_Device), msg->fssm_Unit, (stru
Xct IORequest *)io, msg->fssm_Flags);
X    if (err)
X    {
X        error("Device not opened\n");
X        return FALSE;
X    }
X    DevOpen = TRUE;
X    blk_size = env[DE_SIZEBLOCK];
X    blk_offset = env[DE_LOWCYL] * env[DE_BLKSPERTRACK] * env[DE_NUMHEADS];
X    root_blk = (env[DE_BLKSPERTRACK] * env[DE_NUMHEADS] * (env[DE_UPPERCYL] - e
Xnv[DE_LOWCYL] + 1) - 1 + env[DE_RESERVEDBLKS]) / 2;
X    secbuf = (long *)AllocMem(2 * 4 * blk_size, env[DE_MEMBUFTYPE]);
X    if (!secbuf)
X    {
X        error("No sector buffer!\n");
X        return FALSE;
X    }
X    secbuf2 = secbuf + blk_size;
X    return TRUE;
X}
X
X/* Close device */
Xvoid release(void)
X{
X    if (secbuf) FreeMem((char *)secbuf, 2 * 4 * blk_size);
X    if (DevOpen) CloseDevice((struct IORequest *)io);
X    if (io) DeleteStdIO(io);
X    if (port) DeletePort(port);
X}
X
X/* Displays free blocks on device dev. For OFS/FFS !!! */
Xvoid disp_free(struct DeviceNode *dev)
X{
X    struct FileSysStartupMsg *fmsg = (struct FileSysStartupMsg *)BADDR(dev->dn_
XStartup);
X    ULONG *env = (ULONG *)BADDR(fmsg->fssm_Environ);
X    int quit, bit;
X    struct IntuiMessage *msg;
X    long first, last, numblks, pos, i, blk, word, x, y;
X    int firstx, firsty, lastx, lasty;
X
X    if (prepare_window(dev))
X    {
X        if (!ReadBlock(secbuf, root_blk)) goto diskerror;
X        first = blk_size - 49; last = blk_size - 24; /* extent of bitmap list *
X/
X        numblks = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK] * (env[DE_UPPERCYL] -
X env[DE_LOWCYL] + 1);
X        blk = env[DE_RESERVEDBLKS]; /* First block described in bitmap */
X        pos = first;
X        lasty = -recth - 1; firsty = -1;
X
X        do {
X            if (pos == last) /* End of bitmap table list, read extension bitmap
X table */
X            {
X                if (!ReadBlock(secbuf, secbuf[last])) goto diskerror;
X                pos = first = 0;
X                last = blk_size - 1;
X            }
X            /* Read next bitmap sector */
X            if (!ReadBlock(secbuf2, secbuf[pos++])) goto diskerror;
X
X            /* Display free blocks in it */
X            for (i = 1; blk != numblks && i < blk_size; i++)
X            {
X                word = secbuf2[i];
X                for (bit = 0; blk != numblks && bit < 32; bit++, blk++)
X                {
X                    if (word & 1) /* Free sector */
X                    {
X                        cvt_point(&x, &y, blk);
X                        /* Speed up drawing (by a factor of 3 on HD), check
X                           for consecutive free blocks & draw them in one go */
X     
X                        if (y != lasty + recth || x != lastx)
X                        {
X                            /* Non consecutive blocks, draw */
X
X                            if (firsty != -1)
X                                RectFill(win->RPort, firstx, firsty, lastx + re
Xctw - 1, lasty + recth - 1);
X                            firstx = x; firsty = y;
X                        }
X                        lastx = x; lasty = y;
X                    }
X                    word >>= 1; /* next sector */
X                }
X            }
X        } while (blk != numblks);
X        if (firsty != -1)
X            RectFill(win->RPort, firstx, firsty, lastx + rectw - 1, lasty + rec
Xth - 1);
X        Motor(FALSE); /* Turn drive motor off */
X
X        quit = FALSE;
X        while (!quit)
X        {
X            WaitPort(win->UserPort);
X            while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
X            {
X                quit = msg->Class == CLOSEWINDOW;
X                ReplyMsg((struct Message *)msg);
X            }
X        }
X        CloseWindow(win);
X    }
X    else error("Couldn't open window\n");
X    return;
X
Xdiskerror:
X    CloseWindow(win);
X    error("Error reading disk\n");
X}
X
X/* Display free blocks on partition passed as parm, from CLI only */
Xvoid main(int argc, char **argv)
X{
X    struct DeviceNode *dev;
X
X    cli = (argc != 0);
X
X    if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library"
X, 0L))
X        if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L))
X            if (argc != 2) error("Usage: free <device>\n")
X            else
X            {
X                int l = strlen(argv[1]) - 1;
X
X                if (argv[1][l] != ':') error("Not a device spec!\n")
X                else
X                {
X                    argv[1][l] = '\0';
X                    dev = FindDevice(argv[1]);
X                    if (dev)
X                    {
X                        if (setup(dev)) disp_free(dev);
X                        release();
X                    }
X                    else error("No such device\n");
X                }
X            }
X        else error("No graphics library !\n")
X    else error("No intuition library !\n");
X
X    if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
X    if (GfxBase) CloseLibrary((struct Library *)GfxBase);
X    if (_Backstdout) Close(_Backstdout);
X}
SHAR_EOF
echo "extracting free.doc"
sed 's/^X//' << \SHAR_EOF > free.doc
X    This is a small program to graphically dsplay the free blocks on a disk
X(you can thus see how fragmented it is).
X
XUsage
X-----
X
X    This program runs from the CLI only:
X
X        free <device name>:
X
X        will display the free blocks on the disk in the device specified
X        (you must specify the device, not the name of the disk).
X        Note that this program detaches from the CLI, don't 'RUN' it !
X
X        Example:
X
X            free df0:
X
X    The window opened will be a representation of the disk, with cylinders
X    presented vertically (if possible). The lit pixels represent the free
X    blocks on the disk.
X
X
XDistribution
X------------
X
X    This software is placed in the public domain.
X
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XDavid Gay
X  "(p.suiv :=: q.prec.suiv).prec :=: q.prec"
X  You don't want to know about this language !
X
XGAY_D@ELMA.EPFL.CH, or GAY_D%ELMA.EPFL.CH@CLSEPF51.bitnet
X(till mid-august 89)
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
X
X
SHAR_EOF
echo "extracting free.hdr"
sed 's/^X//' << \SHAR_EOF > free.hdr
XFrom dg3i+@andrew.cmu.edu Sat Nov 11 18:44:13 1989
XDate: Fri, 10 Nov 89 16:08:45 -0500 (EST)
XFrom: David Gay <dg3i+@andrew.cmu.edu>
XTo: page@Sun.COM
XSubject: comp.sources.amiga submission, show disk space
X
X#       This is a shell archive.
X#       Remove everything above and including the cut line.
X#       Then run the rest of the file through sh.
SHAR_EOF
echo "extracting free.uu"
sed 's/^X//' << \SHAR_EOF > free.uu
X
Xbegin 644 free
XM```#\P`````````#``````````(```#*```#0@```-8```/I````RDCG?OY+,
XM[P`T)$@D`$GY`````"QX``0I3@!:*4\`8D*L`%Y'^0```K1R`"`\````*6`"C
XM)L%1R/_\)FX!%'``(CP``#``3J[^SBEK`)@`5DJK`*QG``%080`"G"(L`%8L4
XM;`-(3J[_H"E``%8@:P"LT<C1R")H`!#3R=/)(`)R`!(9*`DF`=*!T(%:@.6(.
XMT*P`%"E``!1![```+'@`!$ZN_R(B0"\`(FD`$$?I`.8@1"`#8`(6V%'(__P6"
XM_``@($H@`F`"%MA1R/_\0ALI2P!V($0@`V`"%MA1R/_\0A-%Z0!L*4H`&D7ZY
XM_Q8B_````#DF">2+(M)"DD7Z`38@/````-T2VE'(__Q*K`">9P``&D'L`(8BK
XM""0\```#[2QL`TA.KO_B*4``<BQX``1.KO]\(BP`EB0L`)HH+`"(+&P#2$ZN;
XM_W8F3DJ`9@``("1?(FH`$"(L`%9.KO^F($HL>``$3J[_''!H8```)B1`(E]%.
XMZO^D0>H`2D'H``0@*``$(4D`!"*((T``!"!`((EP`"QX``1.KO]V(DLL>``$A
XM3J[^8DS??WY.=2EK`#H`)@:L````@``F80`!0$7Z`/`I2@`:80`!3"E``%XO5
XM`"1`("H`)&<2+&P#2"!`(B@``"E!`%9.KO^"(BH`(&<:)#P```/M3J[_XBE`8
XM`&YG"N6(($`G:``(`*0@;`!>+PA(;``B(&@`)"EH``0`=DZZ`0A.N0``#,QPU
XM`&```(0````Y`````"`/2.=^_BI`+'@`!$GY`````"E/`&)A``"ND\DL>``$X
XM3J[^VB9`*6L`.@`F!JP```"``"8@:P"`T<C1R")H``S3R=/)*5$`'B%1``PB)
XM+`!6+&P#2$ZN_X)(>@"$3KD```S,6$\B+``>+&P#2$ZN_V0B+`!63J[_IG``1
XM("P`3F<$($!.D$ZY```,Q"QX``0B;`-(3J[^8DZY```)3DJL`%YG&B(L`&YG-
XM!$ZN_]PL>``$3J[_?")L`%Y.KOZ&+FP`8DS??WY.=4/L`'IP`$ZN_=@I0`-(K
XM9P``!$YU<&1@G$'K`%Q.KOZ`0>L`7$ZN_HQ.=0``3OD```E,<&$```/L````M
XM!0````$```+&```"M````HP```(<```#(@````,````"````)````CP````.*
XM`````````_(```/I```#0DY5__0O"BM`__CE@")`1>D``1(12(%(P2]```0K@
XM2/_\(`$B2DZZ"EX@;P`$$!!(@"!M__Q",```(`@D7TY=3G5.5?_P*T#_]"`L*
XM`R@B+`,X3KH*QB]````@+?_T(B\``$ZZ"M8B+`,L3KH*KE2`((`@+?_T(BP#V
XM.$ZZ"KX@+`,P3KH*EG(*T($B@$Y=3G5.5?_X2.<S$B9(("L`'.6`($`B*``(&
XMY8$@02`H``PB*``43KH*9BX`("@`*)"H`"0L`%*&<$)&`+Z`;B8I1P,X(`8BL
XM/````GQ.N@I@4H`I0`,H(`8B+`,H3KH*4"E``S1@.BE``S@@!B('3KH*'G)"D
XM1@%.N@HV4H`B/````GPO0``83KH*)E*`*4`#*"`O`!@B+`,H3KH*%"E``S1PX
XM9-"`(BP#-$ZZ"@12@"E``RQP4"(L`SA.N@GT4H`I0`,P("L`*$'L`K1A`/ZJ4
XM0>P"M$/L`-).N@DZ0>P"M"E(`+P@+`,L(BP#-$ZZ":)8@#E``*8@+`,P(BP#Y
XM.$ZZ"9!R"]"!.4``J$'L`*(L;`-`3J[_-"E``R1*@&=2($`B:``R<`(L;`-$A
XM3J[^JB!L`R0P*``(2,!7@#(H``I(P56!+T``&"]!`!PB:``R<`)R"B0O`!@FG
XM+P`<3J[^SB!L`R0B:``R<`-.KOZJ<`%@`G``3-](S$Y=3G5.5?_X2.<`$B9(2
XM(&P#"#%\``(`'"%!`"0A2P`H(&P#""%``"PK0/_X*T'__")(+'@`!$ZN_C@@-
XM;`,($"@`'TH`9@0@2V`"D<@@"$S?2`!.74YU3E7__"\.(&P#"#%\``D`'"%`6
XM`"0K0/_\(D@L>``$3J[^."Q?3EU.=4CG`3(F2"!+2AAF_%.(D<LN""QX``1.I
XMKO]\(&P#2"!H`"(@*``8Y8`@0"(H``3E@21!8"Y*J@`$9B(@*@`HY8`@0!(0/
XM2(%(P;*'9A!#Z``!(`<@2TZZ!TY*@&<*(!+E@"1`(`IFSBQX``1.KO]V(`I,_
XMWTR`3G5(YP`R)D@L>``$3J[_?"!L`T@@:``B("@`&.6`($`B*``$Y8$D06`>9
XM2JH`!&82M^H`"&8,+'@`!$ZN_W8@"F`4(!+E@"1`(`IFWBQX``1.KO]V<`!,`
XMWTP`3G5.5?_X(BP#%-*`*T#_^"`L`Q!.N@>XY8`B+`,0Y8$K2/_\80#^DDY=]
XM3G5.5?_82.<P,B9(("L`'.6`)D`@*P`(Y8`D0'``D<A.N@BB*4`#!&8B2JP#V
XM/&<6<`DB+`!R0>P`XB0()@`L;`-(3J[_T'``8``!%B!L`P1.N@@V*4`#"$J`_
XM9BA*K`,\9QQR#R]!`!0B+`!R0>P`]B0()B\`%"QL`TA.KO_0<`!@``#>("L`J
XM!$'M_]QA`/O^($`@$R)L`P@B*P`,+'@`!$ZN_D1*@&<B2JP#/&<6<!(B+`!R9
XM0>P!%B0()@`L;`-(3J[_T'``8```F'`!*4`##"(J``0I00,0("H`)"(J`!1.^
XMN@;"(BH`#$ZZ!KHI0`,4("H`%"(J``Q.N@:J(BH`*)*J`"12@4ZZ!IS0J@`8S
XM4X#BB"E``Q@@+`,0YX`B*@`P+'@`!$ZN_SHI0`,<9B!*K`,\9Q9P$B(L`')!C
XM[`$^)`@F`"QL`TA.KO_0<`!@$B`L`Q#E@"!L`QS1P"E(`R!P`4S?3`Q.74YU#
XM+PY*K`,<9Q(@+`,0YX`B;`,<+'@`!$ZN_RY*K`,,9PPB;`,(+'@`!$ZN_CY**
XMK`,(9P@@;`,(3KH%F$JL`P1G""!L`P1.N@6V+%].=4Y5_\!(YS\R)D@@2R`H5
XM`!SE@")`(BD`".6!)D%A`/M(2H!G``(N("P#&"!L`QQA`/WT2H!G``(Z>NC:5
XMK`,0*T7_["`K``PB*P`43KH%I"(K`"B2JP`D4H%.N@66*"L`&'S/W*P#$"M&1
XM_^@B+`,P1($N`5.'<O\K0?_4+T``)+R%9B0@!>6`(&P#'")(T\`@$6$`_9)*A
XM@&<``=A\`"`L`Q!3@"M`_^P@!E*`(@;E@2!L`QS1P2M`_^@@$"!L`R!A`/UDZ
XM2H!G``&J>@%\!&```+H@;`,@T>W_S"P0>@!@``"0"`8``&<``((@!$'M_^!#Z
XM[?_<80#Z)-ZL`S`@+?_<L(=F#"`M_]`B+?_@LH!G4"`M_]1R_["!9S8B+?_0%
XMTJP#+%.!)`=3@B]!`"@@;`,D(F@`,B`M_]@B+?_4+T(`+"0O`"@F+P`L+&P#"
XM1$ZN_LX@+?_@(BW_W"M`_]@K0?_4*VW_X/_0+BW_W.*&4H52A+BO`"1G"'`@^
XMNH!M`/]F*BW_Y%*%+"W_S%B&*T7_Y"M&_\PL+P`DN(9G"+JL`Q!M`/\R(`8J!
XM+?_L+"W_Z+B`9@#^T"PM_]1P_[R`9S@@+?_0T*P#+%.`(@?2K`,P4X$O0``D5
XM+T$`*"!L`R0B:``R("W_V"(&)"\`)"8O`"@L;`-$3J[^SG``80#[-GX`8$0@R
XM;`,D(&@`5BQX``1.KOZ`8!P,JP```@``%%?`1`!(@$C`+@`B2RQX``1.KOZ&*
XM(&P#)"!H`%8L>``$3J[^C"9`(`MFSDJ'9[@@;`,D+&P#0$ZN_[A@1DJL`SQGW
XM0'`5(BP`<D'L`68D""8`+&P#2$ZN_]!@*"!L`R0L;`-`3J[_N$JL`SQG%G`37
XM(BP`<D'L`9(D""8`+&P#2$ZN_]!,WTS\3EU.=4Y5__Q(YS$R+@`F2$J'5L!$8
XM`$B`2,`I0`,\0^P!NG``+'@`!$ZN_=@I0`-`2H!G``#T0^P!S'``3J[]V"E`"
XM`T1*@&<``+QR`KZ!9RA*K`,\9P``]'(5+T$`&"(L`')![`'>)`@F+P`8+&P#5
XM2$ZN_]!@``#4(&L`!$H89OQ3B)'K``0B"%.!(&L`!-'!)$AR.K(29RA*K`,\T
XM9P``K'(3+T$`&"(L`')![`(*)`@F+P`8+&P#2$ZN_]!@``",0A(@:P`$80#Y)
XM\"9`(`MG%B!+80#ZWDJ`9P8@2V$`_(9A`/PV8&1*K`,\9UYP#R(L`')![`(R8
XM)`@F`"QL`TA.KO_08$9*K`,\9T!R%B]!`!@B+`!R0>P"4B0()B\`&"QL`TA.=
XMKO_08")*K`,\9QQR%R]!`!@B+`!R0>P"@B0()B\`&"QL`TA.KO_02JP#0&<,L
XM(FP#0"QX``1.KOYB2JP#1&<,(FP#1"QX``1.KOYB2JP`<F<,(BP`<BQL`TA.J
XMKO_<3-],C$Y=3G5.=4YU#```86T*#```>FX$!```($YU``!.5?]T2.<!,"9(G
XM?@!P(+Z`;'H0$W(@L`%G#'()L`%G!G(*L`%F!%*+8.A*$V=>(`?E@%*'0>W_4
XM=-'`)$AP(K`39B)2BR2+2A-G"G`BL!-G!%*+8/)*$V8(<`%.N@!48*Q"&V"H@
XM)(M*$V<8$!-R(+`!9Q!R";`!9PIR"K`!9P12BV#D2A-F`F`$0AM@@$J'9P9!C
XM[?]T8`0@;`!>(`=.NOW&<`!.N@`,3-\,@$Y=3G4``$[Y````&````````$Y5+
XM__Q(YP,P)D@D22X`2H=G,DH39RY*$F<J<``0&TZZ_Q!R`!(:+T``$"`!3KK_F
XM`B(O`!"2@"P!2H9G!"`&8!I3AV#*2H=G$$H39P1P`6`*2A)G!'#_8`)P`$S??
XM#,!.74YU```B"&`$$-EG"%.`9/A@!D(84X!D^B`!3G4@"$H89OQ3B!#99OQ.$
XM=0``2.<`$B9(%WP`_P`(,'S__R=(`!0G2``8(DMP,"QX``1.KO\N3-](`$YU&
XM``!(YP`2)DA*JP`*9PHB2RQX``1.KOZ8%WP`_P`(</\G0``4<``0*P`/+'@`H
XM!$ZN_K`B2W`B3J[_+DS?2`!.=0``2.<P`"0`)@%(0DA#Q,'&P,#!U$-(0D)"\
XMT(),WP`,3G5*@&H``!Y$@$J!:@``#$2!80``($2!3G5A```81(!$@4YU2H%JK
XM```,1(%A```&1(!.=2\"2$$T`68``")(0$A!2$(T`&<```:$P3`"2$`T`(3!J
XM,`)(0C(")!].=2\#=A`,00"`9```!N&944,,00@`9```!NF964,,02``9```A
XM!N6954-*06L```;CF5-#-`#FJ$A"0D+FJDA#@,$V`#`"-`-(0<3!D()D```(!
XM4T/0@63^<@`R`TA#Y[A(0,%!)A\D'TYU2.<`,B9((`MF!'``8"9P,"(\``$`(
XM`2QX``1.KO\Z)$`@"F<.%7P`!0`(0BH`"25+``X@"DS?3`!.=0``2.<#,B9(H
XM+@!P_RQX``1.KOZV+``,!@#_9@1P`&!F<"(B/``!``%.KO\Z)$`@"F8*<``0W
XM!DZN_K!@2"5+``H@!Q5```D5?``$``A"*@`.%48`#Y/)3J[^VB5``!`@"V<(7
XM(DI.KOZ>8!I!Z@`8)4@`%$'J`!0E2``<0JH`&!5\``(`("`*3-],P$YU``!@%
XM```23G$``"!O``1@`/R23G$``$CG`#(F;`-,(`MG%"13(DL@*P`(+'@`!$ZN4
XM_RXF2F#HD<@I2`-0*4@#3$S?3`!.=0```^P````!`````@``"A8````````#1
XM\@```^H```"M`````````````````````0````$```#F3OD`````````````[
XM`````````````````````````````````````````````````````````````
XM``````````````````````````````````````````````````````!D;W,NT
XM;&EB<F%R>0`J````!]!F<F5E8FQK<P``````C``````````!``````````#_0
XM_P```@```P`.```````````````````````````````````````!.BP@9G)E6
XM92!B;&]C:W,``$YO('!O<G0A"@!.;R!P;W)T(0H`3F\@24\@<F5Q=65S="$*F
XM`$YO($E/(')E<75E<W0A"@!$979I8V4@;F]T(&]P96YE9`H``$1E=FEC92!N-
XM;W0@;W!E;F5D"@``3F\@<V5C=&]R(&)U9F9E<B$*``!.;R!S96-T;W(@8G5F$
XM9F5R(0H``$-O=6QD;B=T(&]P96X@=VEN9&]W"@!#;W5L9&XG="!O<&5N('=I.
XM;F1O=PH`17)R;W(@<F5A9&EN9R!D:7-K"@!%<G)O<B!R96%D:6YG(&1I<VL*T
XM`&EN='5I=&EO;BYL:6)R87)Y`&=R87!H:6-S+FQI8G)A<GD``%5S86=E.B!FO
XM<F5E(#QD979I8V4^"@!5<V%G93H@9G)E92`\9&5V:6-E/@H`3F]T(&$@9&5VF
XM:6-E('-P96,A"@!.;W0@82!D979I8V4@<W!E8R$*`$YO('-U8V@@9&5V:6-E_
XM"@!.;R!S=6-H(&1E=FEC90H`3F\@9W)A<&AI8W,@;&EB<F%R>2`A"@``3F\@?
XM9W)A<&AI8W,@;&EB<F%R>2`A"@``3F\@:6YT=6ET:6]N(&QI8G)A<GD@(0H`1
XM3F\@:6YT=6ET:6]N(&QI8G)A<GD@(0H```````/L`````0````(```"6````H
X%`````_)TI
X``
Xend
Xsize 5000
SHAR_EOF
echo "extracting blocks.c"
sed 's/^X//' << \SHAR_EOF > blocks.c
X#include <exec/types.h>
X#include <exec/io.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <libraries/filehandler.h>
X#include <intuition/intuition.h>
X#include <workbench/startup.h>
X
X#include <proto/exec.h>
X#include <proto/dos.h>
X#include <proto/graphics.h>
X#include <proto/intuition.h>
X
X#include <stdio.h>
X#include <string.h>
X
X#define error(s) { if (cli) Write(_Backstdout, (s), strlen(s)); }
X
X#define USAGE "blocks <filename>\n"
X/* border sizes */
X#define XLEFT 2
X#define XRIGHT 2
X#define YTOP 10
X#define YBOTTOM 1
X/* Min & Max size for window */
X#define MAXHEIGHT (200 - YTOP - YBOTTOM)
X#define MAXWIDTH   (640 - XLEFT - XRIGHT)
X#define MINWIDTH 200
X#define MINHEIGHT 80
X
X/* Spawn info */
Xlong _stack = 2000;
Xchar *_procname = "blocks";
Xlong _priority = 0;
Xlong _BackGroundIO = TRUE;
Xextern long _Backstdout;
X
Xtypedef struct FileInfoBlock FIB;
Xtypedef struct InfoData INFO;
X
Xextern struct IntuitionBase *IntuitionBase;
Xextern struct GfxBase *GfxBase;
X
X/* For io to device */
Xstruct MsgPort *port;
Xstruct IOStdReq *io;
Xint DevOpen;
X/* Device info */
Xlong blk_size, blk_offset, root_blk, *secbuf;
Xstruct Window *win;
X/* size of window, of each block, etc */
Xint xdiv, rectw, recth, width, height;
Xint cli; /* Called from cli ? */
X
Xstruct NewWindow newwin = {
X    0, 0,
X    0, 0,
X    -1, -1,
X    CLOSEWINDOW,
X    WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | NOCAREREFRESH | RM
XBTRAP,
X    NULL,
X    NULL,
X    NULL,
X    NULL,
X    NULL,
X    0, 0, 0, 0,
X    WBENCHSCREEN
X};
X
X/* Calculate coords on window for block 'block' on disk */
Xvoid cvt_point(x, y, block)
Xlong *x, *y, block;
X{
X    *x = rectw * (block / (xdiv * height)) + XLEFT;
X    *y = recth * (block % height) + YTOP;
X}
X
X/* Calc size, & open window */
Xint prepare_window(fib, dev)
Xstruct FileInfoBlock *fib;
Xstruct DeviceNode *dev;
X{
X    /* Get disk characteristics */
X    struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S
Xtartup);
X    ULONG *env = (ULONG *)BADDR(msg->fssm_Environ);
X    long blkscyl = env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
X    long numcyls = env[DE_UPPERCYL] - env[DE_LOWCYL] + 1;
X    long blks;
X    static char title[80];
X
X    if (blkscyl <= MAXHEIGHT) /* Do a "nice" presentation, 1 cylinder per vert
Xline */
X    {
X        height = blkscyl;
X        xdiv = (numcyls / MAXWIDTH + 1); /* Nb of cylinders per vertical line *
X/
X        width = numcyls / xdiv;
X    }
X    else /* Just squash em in */
X    {
X        blks = numcyls * blkscyl;
X        height = MAXHEIGHT;
X        xdiv = (blks / MAXHEIGHT + 1) / MAXWIDTH + 1;
X        width = (blks / MAXHEIGHT + 1) / xdiv;
X    }
X    /* Size of rect for 1 block */
X    rectw = MINWIDTH / width + 1;
X    recth = MINHEIGHT / height + 1;
X
X    /* Open window */
X    sprintf(title, "File: %s, %ld blocks", fib->fib_FileName, fib->fib_NumBlock
Xs);
X    newwin.Title = title;
X    newwin.Width = rectw * width + XLEFT + XRIGHT;
X    newwin.Height = recth * height + YTOP + YBOTTOM;
X
X    if (win = OpenWindow(&newwin))
X    {
X        SetAPen(win->RPort, 2);
X        RectFill(win->RPort, XLEFT, YTOP, win->Width - XRIGHT - 1, win->Height
X- YBOTTOM - 1);
X        SetAPen(win->RPort, 3);
X        return TRUE;
X    }
X    return FALSE;
X}
X
X/* bstr -> cstr */
Xchar *btoc_str(to, from)
Xchar *to;
XBSTR from;
X{
X    char *cstr = (char *)BADDR(from);
X
X    strncpy(to, cstr + 1, *cstr);
X    to[*cstr] = '\0';
X
X    return to;
X}
X
X/* Reads sector at offset 'sector' from disk ('sector' must be a multiple of 51
X2) */
XBYTE *ReadSector(sector, buf, len)
Xlong sector;
XBYTE *buf;
Xlong len;
X{
X    io->io_Command = CMD_READ;
X    io->io_Length = len;
X    io->io_Data = (APTR)buf;
X    io->io_Offset = sector;
X    DoIO((struct IORequest *)io);
X    return (io->io_Error == 0) ? buf : NULL;
X}
X
X/* Find device by task */
Xstruct DeviceNode *TaskDevice(task)
Xstruct MsgPort *task;
X{
X    struct DeviceNode *devlist;
X
X    Forbid();
X    devlist = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct Root
XNode *)(DOSBase->dl_Root))->rn_Info))->di_DevInfo);
X    for (;devlist; devlist = (struct DeviceNode *)BADDR(devlist->dn_Next))
X        if (devlist->dn_Type == DLT_DEVICE)
X        {
X            if (task == devlist->dn_Task) { Permit(); return devlist; }
X        }
X
X    Permit();
X    return NULL;
X}
X
X/* Reads block n of *partition* */
Xvoid ReadBlock(n)
Xlong n;
X{
X    ReadSector((blk_offset + n) * blk_size * 4, secbuf, blk_size * 4);
X}
X
X/* Get partition characteristics, open device */
Xint setup(dev)
Xstruct DeviceNode *dev;
X{
X    char devname[32];
X    struct FileSysStartupMsg *msg = (struct FileSysStartupMsg *)BADDR(dev->dn_S
Xtartup);
X    ULONG *env = (ULONG *)BADDR(msg->fssm_Environ);
X    long err;
X
X    port = CreatePort(0, 0);
X    if (!port)
X    {
X        error("No port!\n");
X        return FALSE;
X    }
X    io = CreateStdIO(port);
X    if (!io)
X    {
X        error("No IO request!\n");
X        return FALSE;
X    }
X    err = OpenDevice(btoc_str(devname, msg->fssm_Device), msg->fssm_Unit, (stru
Xct IORequest *)io, msg->fssm_Flags);
X    if (err)
X    {
X        error("Device not opened\n");
X        return FALSE;
X    }
X    DevOpen = TRUE;
X    blk_size = env[DE_SIZEBLOCK];
X    blk_offset = env[DE_LOWCYL] * env[DE_BLKSPERTRACK] * env[DE_NUMHEADS];
X    root_blk = (env[DE_BLKSPERTRACK] * env[DE_NUMHEADS] * (env[DE_UPPERCYL] - e
Xnv[DE_LOWCYL] + 1) - 1 + env[DE_RESERVEDBLKS]) / 2;
X    secbuf = (long *)AllocMem(4 * blk_size, env[DE_MEMBUFTYPE]);
X    if (!secbuf)
X    {
X        error("No sector buffer!\n");
X        return FALSE;
X    }
X    return TRUE;
X}
X
X/* Close device */
Xvoid release()
X{
X    if (secbuf) FreeMem((char *)secbuf, 4 * blk_size);
X    if (DevOpen) CloseDevice((struct IORequest *)io);
X    if (io) DeleteStdIO(io);
X    if (port) DeletePort(port);
X}
X
X/* Displays blocks used by file described by fib */
X/* For OFS/FFS !!! */
Xvoid get_blocks(fib, node, device)
XFIB *fib;
Xstruct DeviceList *node;
Xstruct DeviceNode *device;
X{
X    long key = fib->fib_DiskKey, data1 = blk_size - 51, used, i, x, y;
X    int quit;
X    struct IntuiMessage *msg;
X
X    if (prepare_window(fib, device))
X    {
X        do {
X            Forbid();
X            if (device->dn_Task != node->dl_Task)
X            {
X                error("Disk not in drive!\n");
X                break;
X            }
X            ReadBlock(key); /* Read either File header or file list block */
X            Permit();
X            used = secbuf[2]; /* num blocks described here */
X            /* Draw blocks */
X            for (i = 0; i < used; i++)
X            {
X                cvt_point(&x, &y, secbuf[data1 - i]);
X                RectFill(win->RPort, x, y, x + rectw - 1, y + recth - 1);
X            }
X            /* Extension blocks ? */
X            key = secbuf[blk_size - 2];
X        } while (key != 0);
X
X        /* Wait for window close */
X        quit = FALSE;
X        while (!quit)
X        {
X            WaitPort(win->UserPort);
X            while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
X            {
X                quit = msg->Class == CLOSEWINDOW;
X                ReplyMsg((struct Message *)msg);
X            }
X        }
X        CloseWindow(win);
X    }
X}
X
X/* Display blocks used by file name */
Xvoid disp_blocks(name)
Xchar *name;
X{
X    FIB *fib = (FIB *)AllocMem(sizeof(FIB), 0L);
X    INFO *info = (INFO *)AllocMem(sizeof(INFO), 0L);
X    BPTR lock = Lock(name, SHARED_LOCK);
X    struct DeviceList *node;
X    struct DeviceNode *device;
X
X    if (fib && info)
X        if (lock)
X            if (Info(lock, info) && Examine(lock, fib))
X                if (fib->fib_DirEntryType >= 0) error("Only for files!\n")
X                else if (info->id_UnitNumber < 0) error("Only on OFS or FFS dis
Xks\n") /* Test detects RAM: ... */
X                else
X                {
X                    node = (struct DeviceList *)BADDR(info->id_VolumeNode);
X                    if (node == 0) error("Disk not in drive\n")
X                    else
X                        if (device = TaskDevice(node->dl_Task))
X                        {
X                            if (setup(device)) get_blocks(fib, node, device);
X                            release();
X                        }
X                        else error("Couldn't find disk's device!\n")
X                }
X            else error("Couldn't get info on file\n")
X        else error("No such file\n")
X    else error("No memory !\n");
X
X    if (lock) UnLock(lock);
X    if (fib) FreeMem((char *)fib, sizeof(FIB));
X    if (info) FreeMem((char *)info, sizeof(INFO));
X}
X
X/* Display blocks used by files passed as parms
X   Works from WB or CLI */
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X    int i;
X
X    cli = (argc != 0);
X
X    if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library"
X, 0L))
X        if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L))
X            if (argc == 0) /* WB */
X            {
X                struct WBStartup *msg = (struct WBStartup *)argv;
X
X                for (i = 1; i < msg->sm_NumArgs; i++)
X                    if (msg->sm_ArgList[i].wa_Name[0] != '\0') /* A dir */
X                    {
X                        CurrentDir(msg->sm_ArgList[i].wa_Lock);
X                        disp_blocks(msg->sm_ArgList[i].wa_Name);
X                    }
X            }
X            else if (argc == 1) error(USAGE)
X            else
X                for (i = 1; i < argc; i++) disp_blocks(argv[i]);
X        else error("No graphics library !\n")
X    else error("No intuition library !\n");
X
X    if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
X    if (GfxBase) CloseLibrary((struct Library *)GfxBase);
X    if (_Backstdout) Close(_Backstdout);
X}
SHAR_EOF
echo "extracting blocks.doc"
sed 's/^X//' << \SHAR_EOF > blocks.doc
X    This is a small program to graphically dsplay the blocks used by a file
X(you can thus see how fragmented it is).
X
XUsage
X-----
X
X    from the CLI:
X
X        blocks <file1> <file2> ...
X
X        will display the blocks used by file1, file2, ...
X        Note that this program detaches from the CLI, don't 'RUN' it !
X
X    from the WB:
X
X        click on the icon for blocks (non provided, sorry!), then
X        select the other icons of the files you want, double-clicking
X        on the last one (you will have to hold the shift key down, of
X        course).
X
X
X    A window will be opened for the first file, when you close it, another
X    one for the second file will appear, and so on.
X
X    The window opened will be a representation of the disk containing the
X    file, with cylinders presented vertically (if possible). The lit
X    pixels represent the blocks used by the file.
X
X
XDistribution
X------------
X
X    This software is placed in the public domain.
X
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
XDavid Gay
X  "(p.suiv :=: q.prec.suiv).prec :=: q.prec"
X  You don't want to know about this language !
X
XGAY_D@ELMA.EPFL.CH, or GAY_D%ELMA.EPFL.CH@CLSEPF51.bitnet
X(till mid-august 89)
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
X
X
SHAR_EOF
echo "extracting blocks.uu"
sed 's/^X//' << \SHAR_EOF > blocks.uu
X
Xbegin 644 blocks
XM```#\P`````````#``````````(```#*```$>@```48```/I````RDCG?OY+V
XM[P`T)$@D`$GY`````"QX``0I3@!:*4\`8D*L`%Y'^0``!'!R`"`\````*F`"B
XM)L%1R/_\)FX!%'``(CP``#``3J[^SBEK`)@`5DJK`*QG``%080`"G"(L`%8L4
XM;`4(3J[_H"E``%8@:P"LT<C1R")H`!#3R=/)(`)R`!(9*`DF`=*!T(%:@.6(0
XMT*P`%"E``!1![```+'@`!$ZN_R(B0"\`(FD`$$?I`.8@1"`#8`(6V%'(__P6"
XM_``@($H@`F`"%MA1R/_\0ALI2P!V($0@`V`"%MA1R/_\0A-%Z0!L*4H`&D7ZY
XM_Q8B_````#DF">2+(M)"DD7Z`38@/````-T2VE'(__Q*K`"<9P``&D'L`(8BI
XM""0\```#[2QL!0A.KO_B*4``<BQX``1.KO]\(BP`E"0L`)@H+`"(+&P%"$ZN;
XM_W8F3DJ`9@``("1?(FH`$"(L`%9.KO^F($HL>``$3J[_''!H8```)B1`(E]%.
XMZO^D0>H`2D'H``0@*``$(4D`!"*((T``!"!`((EP`"QX``1.KO]V(DLL>``$A
XM3J[^8DS??WY.=2EK`#H`)@:L````@``F80`!0$7Z`/`I2@`:80`!3"E``%XO5
XM`"1`("H`)&<2+&P%""!`(B@``"E!`%9.KO^"(BH`(&<:)#P```/M3J[_XBE`:
XM`&YG"N6(($`G:``(`*0@;`!>+PA(;``B(&@`)"EH``0`=DZZ`0A.N0``#3!P:
XM`&```(0````Y`````"`/2.=^_BI`+'@`!$GY`````"E/`&)A``"ND\DL>``$X
XM3J[^VB9`*6L`.@`F!JP```"``"8@:P"`T<C1R")H``S3R=/)*5$`'B%1``PB)
XM+`!6+&P%"$ZN_X)(>@"$3KD```TP6$\B+``>+&P%"$ZN_V0B+`!63J[_IG``Z
XM("P`3F<$($!.D$ZY```1N"QX``0B;`4(3J[^8DZY```(UDJL`%YG&B(L`&YG/
XM!$ZN_]PL>``$3J[_?")L`%Y.KOZ&+FP`8DS??WY.=4/L`'IP`$ZN_=@I0`4(M
XM9P``!$YU<&1@G$'K`%Q.KOZ`0>L`7$ZN_HQ.=0``3OD```C4<&$```/L````T
XM!0````$```+&```"M````HP```(<```#(@````,````"````)````CP````.*
XM`````````_(```/I```$>DY5__P@+`3@(BP$\$ZZ#_HO0```("T`$"(O``!.K
XMNA`*(BP$Y$ZZ#^)4@"!M``@@@"`M`!`B+`3P3KH/[B`L!.A.N@_&<@K0@2!M?
XM``P@@$Y=3G5.5?_P2.<S`B!M``P@*``<Y8`@0"(H``CE@2!!("@`#"(H`!1.K
XMN@^0+@`@*``HD*@`)"P`4H9P0D8`OH!N)BE'!/`@!B(\```"?$ZZ#XI2@"E`C
XM!.`@!B(L!.!.N@]Z*4`$[&`Z*4`$\"`&(@=.N@](<D)&`4ZZ#V!2@"(\```"O
XM?"]``!1.N@]04H`I0`3@("\`%"(L!.!.N@\^*4`$['!DT(`B+`3L3KH/+E*`!
XM*4`$Y'!0(BP$\$ZZ#QY2@"E`!.@@;0`(4(@B;0`(+RD`@"\(2&P`T$AL!'!.\
XMN@XV3^\`$$'L!'`I2`"Z("P$Y"(L!.Q.N@[$6(`Y0`"D("P$Z"(L!/!.N@ZR;
XM<@O0@3E``*9![`"@+&P%`$ZN_S0I0`3<2H!G4B!`(F@`,G`"+&P%!$ZN_JH@%
XM;`3<,"@`"$C`5X`R*``*2,%5@2]``!0O00`8(F@`,G`"<@HD+P`4)B\`&$ZN3
XM_LX@;`3<(F@`,G`#3J[^JG`!8`)P`$S?0,Q.74YU3E7__"`M``SE@"!`0^@`:
XM`1(02(%(P2\!+PDO+0`(+T``#$ZZ#$@@;P`,$!!(@"!M``A",```(`A.74YUX
XM3E4``$CG`!(F;P`4(&P$Q#%\``(`'"%M`!``)"%+`"@@;`3$(6T`"``L(D@LN
XM>``$3J[^."!L!,00*``?2@!F!"!+8`*1R"`(3-](`$Y=3G5(YP`R)F\`$"QXF
XM``1.KO]\(&P%""!H`"(@*``8Y8`@0"(H``3E@21!8!Y*J@`$9A*WZ@`(9@PLQ
XM>``$3J[_=B`*8!0@$N6`)$`@"F;>+'@`!$ZN_W9P`$S?3`!.=4Y5```@+`30Z
XMT*T`""(L!,Q.N@T^Y8`B+`3,Y8$O`2\L!-@O`&$`_RY.74YU3E7_V$CG,#(FB
XM;P!$("L`'.6`)D`@*P`(Y8`D0$*G0J=.N@XB4$\I0`3`9B)*K`3T9Q9P"2(L1
XM`')![`#F)`@F`"QL!0A.KO_0<`!@``$*+RP$P$ZZ#;183RE`!,1*@&8H2JP$T
XM]&<<<@\O00`4(BP`<D'L`/HD""8O`!0L;`4(3J[_T'``8```T"\K``1(;?_<V
XM80#^6E!/($`@$R)L!,0B*P`,+'@`!$ZN_D1*@&<B2JP$]&<6<!(B+`!R0>P!N
XM&B0()@`L;`4(3J[_T'``8```B'`!*4`$R"(J``0I003,("H`)"(J`!1.N@P\"
XM(BH`#$ZZ##0I0`30("H`%"(J``Q.N@PD(BH`*)*J`"12@4ZZ#!;0J@`84X#BC
XMB"E`!-0@+`3,Y8`B*@`P+'@`!$ZN_SHI0`389B!*K`3T9Q9P$B(L`')![`%"+
XM)`@F`"QL!0A.KO_0<`!@`G`!3-],#$Y=3G4O#DJL!-AG$B`L!,SE@")L!-@L5
XM>``$3J[_+DJL!,AG#")L!,0L>``$3J[^/DJL!,1G"B\L!,1.N@LB6$]*K`3`X
XM9PHO+`3`3KH+/EA/+%].=4Y5_^A(YS<R)F\`1"1O`$@@;0`(+A!\S=RL!,PO/
XM"B\(80#[GE!/2H!G``$6+'@`!$ZN_WP@:@`(L>L`"&<B2JP$]&<``*1P$R(L*
XM`')![`%J)`@F`"QL!0A.KO_08```BB\'80#]PEA/+'@`!$ZN_W8@;`38+B@`*
XM"'H`8%(@!I"%Y8`@;`38T<`O$$AM_^Q(;?_P80#ZVD_O``P@+?_P(BP$Y-*`3
XM4X$D+?_L)BP$Z-:"4X,O00`@(&P$W")H`#(B`B0O`"`L;`4$3J[^SE*%NH=MY
XMJB`L!,SE@"!L!-C1P"XH__A*AV8`_T9^`&!$(&P$W"!H`%8L>``$3J[^@&`<W
XM#*H```(``!17P$0`2(!(P"X`(DHL>``$3J[^AB!L!-P@:`!6+'@`!$ZN_HPD5
XM0"`*9LY*AV>X(&P$W"QL!0!.KO^X3-],[$Y=3G5.5?_X2.<Q,B9O`"@@/```@
XM`01R`"QX``1.KO\Z+T``''`D<@!.KO\Z)$`@2B](`!@B"W3^+&P%"$ZN_ZPN0
XM`$JO`!QG``$R(`IG``$L2H=G``$,(@<D"DZN_XY*@&<``.0B!R0O`!Q.KO^:4
XM2H!G``#4(&\`'"`H``1*@&L>2JP$]&<``0QP$"(L`')#[`&2)`DF`$ZN_]!@Q
XM``#V("H`!$J`:AY*K`3T9P``YG`9(BP`<D/L`;8D"28`3J[_T&```-`@*@`<T
XMY8`F0"`+9AY*K`3T9P``O'`2(BP`<D/L`>HD"28`3J[_T&```*8O*P`(80#[)
XMDEA/)$`@"F<F+PIA`/P,6$]*@&<0+PHO"R\O`"1A`/VH3^\`#&$`_5`D;P`8\
XM8&XD;P`82JP$]&=D<!TB+`!R0>P"$B0()@`L;`4(3J[_T&!,2JP$]&=&<!HBU
XM+`!R0>P"3B0()@!.KO_08#)*K`3T9RQP#2(L`')![`*&)`@F`$ZN_]!@&$JL(
XM!/1G$G`,(BP`<D'L`J(D""8`3J[_T$J'9PHB!RQL!0A.KO^F2J\`'&<2(F\`K
XM'"`\```!!"QX``1.KO\N(`IG#")*<"0L>``$3J[_+DS?3(Q.74YU2.<S$BXO^
XM`!PF;P`@2H=6P$0`2(!(P"E`!/1#[`*^<``L>``$3J[]V"E`!0!G``"H0^P"S
XMT'``3J[]V"E`!01G>$J'9CI^`7P(8"P@:P`DT<8B:``$2A%G&B(0+&P%"$ZNE
XM_X(@:P`DT<8O*``$80#]QEA/4H=0AKZK`!QMSF!T<`&^@&8>2JP$]&=H<!(B$
XM+`!R0>P"XB0()@`L;`4(3J[_T&!0+`!8BV`*+QMA`/V(6$]2AKR';?)@.DJL[
XM!/1G-'`6(BP`<D'L`PHD""8`+&P%"$ZN_]!@'$JL!/1G%G`7(BP`<D'L`SHD1
XM""8`+&P%"$ZN_]!*K`4`9PPB;`4`+'@`!$ZN_F)*K`4$9PPB;`4$+'@`!$ZN0
XM_F)*K`!R9PPB+`!R+&P%"$ZN_]Q,WTC,3G5.=4YU3E7_Q$CG)S`F;P!<)&\`O
XM8'X`?`!Z`'``&WP`(/_[<@`K0?_V=/\K0O_R0>W_T!M`__$;0/_\*T'_Y"M!R
XM_^@K2/_,2A-G0G``$!-R&%U!:SBP>Q`(9O9.^Q`$`"-@```@`"!@```6`"M@)
XM```,`"U@```"?@%@#GP!8`IZ`6`&&WP``?_\4HM@NA`3<C"P`68&4HL;0?_[O
XM<"JP$V80(%)#Z``$)(DK4/_V4HM@#DAM__8O"TZZ!7!03]?`$!-R+K`!9B92%
XMBW`JL!-F$"!20^@`!"2)*U#_\E*+8`Y(;?_R+PM.N@5"4$_7P!`3<FRP`68*J
XM&WP``?_Q4HM@"')HL`%F`E*+$!MR`!(`&T#_\'`P74!K``)4LGL`"&;T3OL`L
XM!`!C8``"*@!S8``!Z`!88``!?@!X8``!>`!P8``!7@!O8``!#`!U8```X@!D=
XM8````DHM__%G#"!20^@`!"2)(!!@"B!20^@`!"2)(!`K0/_L;`IR`42M_^PKH
XM0?_H2JW_Z&<$<"U@"DH&9P1P*V`"<"`;0/_0<``0!B(M_^B"@'``$`6"@&<(>
XM4JW_S%*M_^0O+?_L+RW_S$ZZ`])03RM`_\@@+?_R2H!J!G(!*T'_\B`M_\@B&
XM+?_RDH!([0`"_\1O+B!M_\PB2-/!8`(2V%.`9/IP`!`M__LB+?_$(&W_S&`"-
XM$,!3@63Z("W_\BM`_\C1K?_D0>W_T"M(_\Q*!V<``5`;?``@__M@``%&2BW_E
XM\6<,(%)#Z``$)(D@$&`*(%)#Z``$)(D@$"M`_^Q@`/]B2BW_\6<,(%)#Z``$<
XM)(D@$&`*(%)#Z``$)(D@$"M`_^Q*+?_\9Q(@;?_,$/P`,'(!*T'_Y"M(_\PO)
XM`"\M_\Q.N@,L4$\K0/_(8`#_*!M\`##_^R`M__)*@&H&<`@K0/_R2BW_\6<,=
XM(%)#Z``$)(D@$&`*(%)#Z``$)(D@$"M`_^Q*+?_\9Q8@;?_,$/P`,!#\`'ARU
XM`BM!_^0K2/_,+P`O+?_,3KH#"%!/*T#_R'!8L"W_\&8`_KY(;?_03KH"&%A/,
XM8`#^L"!20^@`!"2)(E`K2?_,9@A!^@#<*TC_S"!M_\Q*&&;\4XB1[?_,*TC_"
XMY"`M__)*@&LJL<!O)BM`_^1@('`!*T#_Y"!20^@`!"2)(!`;0/_00BW_T6`&A
XM<`!@``",("W_Y"(M__:R@&P(=``K0O_V8`21K?_V2@=G-E.M_^1M&'``(&W_U
XMS!`8+P`K2/_,(&T`$$Z06$]@XE.M__9M2'``$"W_^R\`(&T`$$Z06$]@Z%.MO
XM__9M$G``$"W_^R\`(&T`$$Z06$]@Z%.M_^1M&'``(&W_S!`8+P`K2/_,(&T`&
XM$$Z06$]@XB`+3-\,Y$Y=3G4``$Y5__9(YP$P)F\`'B1O`"(K;0`0__8>&DH'1
XM9S1P);X`9B*P$F8$4HI@&B\+2&W_]B\*80#[S$_O``PK0/_Z9P0D0&#2<``0L
XM!R\`3I-83V#&3-\,@$Y=3G5.5?]T2.<!,"9O`*!^`'`@OH!L``""$!-R(+`!4
XM9PQR";`!9P9R"K`!9@12BV#H2A-G9"`'Y8!2AT'M_W31P"1(<"*P$V8F4HLD5
XMBTH39PIP(K`39P12BV#R2A-F#$AX``%.N@!:6$]@ID(;8*(DBTH39Q@0$W(@&
XML`%G$'()L`%G"G(*L`%G!%*+8.1*$V8"8`9"&V``_WI*AV<&0>W_=&`$(&P`N
XM7B\(+P=.NOG,0I=.N@`,3.T,@/]H3EU.=4[Y````&````````$CG(#`F;P`0B
XM)$M*$F<D<``0$D'L`VT(,``!"`!G"G(`$@!T()*"8`1R`!(`%(%2BF#8(`M,K
XMWPP$3G4``````````'!A(F\`""!O``0@+P`,(@A@!!#99PA3@&3X8`9"&%.`R
XM9/H@`4YU("\`""!O``1.5?_T(D]R"DZZ`>@&00`P$L%*@&;P(`D0X;_)9OI".
XM$)"/3EU.=0``("\`""!O``1.5?_T(D\B``)!``<&00`P$L'FB&;P(`D0X;_)J
XM9OI"$)"/3EU.=0``,#$R,S0U-C<X.6%B8V1E9B`O``@@;P`$0^\`!#(``D$`V
XM#Q+[$-SHB&;R(`DB#UB!$.&RB6;Z0A"0@4YU(&\`!")(<@!P`"\"#!``*V<&Y
XM#!``+68"4D@0&`0``#!M$@P```EN#"0!Y8'2@M*!TH!@Y@P1`"UF`D2!)!\@9
XM"%.`(&\`"""!D(E.=2\'+B\`"%*L!/P@!R!L!/@0P"E(!/@N'TYU3E4``$CG6
XM`#`F;P`0)&\`%$*L!/PI2P3X2&T`$"\*2'K_QDZZ_5(@;`3X0A`@+`3\3.T,A
XM`/_X3EU.=4CG`!(F;P`,%WP`_P`(,'S__R=(`!0G2``8(DMP,"QX``1.KO\NS
XM3-](`$YU2.<`$B9O``Q*JP`*9PHB2RQX``1.KOZ8%WP`_P`(</\G0``4<``0S
XM*P`/+'@`!$ZN_K`B2W`B3J[_+DS?2`!.=4CG,``D`"8!2$)(0\3!QL#`P=1#,
XM2$)"0M""3-\`#$YU2H!J```>1(!*@6H```Q$@6$``"!$@4YU80``&$2`1(%./
XM=4J!:@``#$2!80``!D2`3G4O`DA!-`%F```B2$!(04A"-`!G```&A,$P`DA`;
XM-`"$P3`"2$(R`B0?3G4O`W80#$$`@&0```;AF5%##$$(`&0```;IF5E##$$@V
XM`&0```;EF55#2D%K```&XYE30S0`YJA(0D)"YJI(0X#!-@`P`C0#2$'$P9""Y
XM9```"%-#T(%D_G(`,@-(0^>X2$#!028?)!].=4CG`#(F;P`0(`MF!'``8"9P<
XM,"(\``$``2QX``1.KO\Z)$`@"F<.%7P`!0`(0BH`"25+``X@"DS?3`!.=4CG4
XM`S(F;P`8+B\`''#_+'@`!$ZN_K8L``P&`/]F!'``8&9P(B(\``$``4ZN_SHD*
XM0"`*9@IP`!`&3J[^L&!()4L`"B`'%4``"15\``0`"$(J``X51@`/D\E.KO[:B
XM)4``$"`+9P@B2DZN_IY@&D'J`!@E2``40>H`%"5(`!Q"J@`8%7P``@`@(`I,&
XMWTS`3G4``$CG`#(F;`4,(`MG%"13(DL@*P`(+'@`!$ZN_RXF2F#HD<@I2`40W
XM*4@%#$S?3`!.=0```^P````!`````@``#>X````````#\@```^H```$<````H
XM`````````````````0````$```#F3OD`````````````````````````````O
XM`````````````````````````````````````````````````````````````
XM``````````````````````````````````````!D;W,N;&EB<F%R>0`J````3
XM!]!B;&]C:W,``````(P``````````0``````````__\```(```,`#@``````S
XM`````````````````````````````````49I;&4Z("5S+"`E;&0@8FQO8VMS2
XM``!.;R!P;W)T(0H`3F\@<&]R="$*`$YO($E/(')E<75E<W0A"@!.;R!)3R!RJ
XM97%U97-T(0H`1&5V:6-E(&YO="!O<&5N960*``!$979I8V4@;F]T(&]P96YE@
XM9`H``$YO('-E8W1O<B!B=69F97(A"@``3F\@<V5C=&]R(&)U9F9E<B$*``!$6
XM:7-K(&YO="!I;B!D<FEV92$*`$1I<VL@;F]T(&EN(&1R:79E(0H`3VYL>2!F4
XM;W(@9FEL97,A"@``3VYL>2!F;W(@9FEL97,A"@``3VYL>2!O;B!/1E,@;W(@N
XM1D93(&1I<VMS"@!/;FQY(&]N($]&4R!O<B!&1E,@9&ES:W,*`$1I<VL@;F]T2
XM(&EN(&1R:79E"@``1&ES:R!N;W0@:6X@9')I=F4*``!#;W5L9&XG="!F:6YDS
XM(&1I<VLG<R!D979I8V4A"@!#;W5L9&XG="!F:6YD(&1I<VLG<R!D979I8V4AW
XM"@!#;W5L9&XG="!G970@:6YF;R!O;B!F:6QE"@``0V]U;&1N)W0@9V5T(&EN4
XM9F\@;VX@9FEL90H``$YO('-U8V@@9FEL90H`3F\@<W5C:"!F:6QE"@!.;R!M:
XM96UO<GD@(0H``$YO(&UE;6]R>2`A"@``:6YT=6ET:6]N+FQI8G)A<GD`9W)AX
XM<&AI8W,N;&EB<F%R>0``8FQO8VMS(#QF:6QE;F%M93X*``!B;&]C:W,@/&9I&
XM;&5N86UE/@H``$YO(&=R87!H:6-S(&QI8G)A<GD@(0H``$YO(&=R87!H:6-SV
XM(&QI8G)A<GD@(0H``$YO(&EN='5I=&EO;B!L:6)R87)Y("$*`$YO(&EN='5I&
XM=&EO;B!L:6)R87)Y("$*`````"`@("`@("`@("@H*"@H("`@("`@("`@("`@"
XM("`@("`@2!`0$!`0$!`0$!`0$!`0$(2$A(2$A(2$A(00$!`0$!`0@8&!@8&!6
XM`0$!`0$!`0$!`0$!`0$!`0$!`0$0$!`0$!""@H*"@H("`@("`@("`@("`@(":
XM`@("`@("`A`0$!`@("`@("`@("`@*"@H*"@@("`@("`@("`@("`@("`@("!(>
XM$!`0$!`0$!`0$!`0$!`0A(2$A(2$A(2$A!`0$!`0$!"!@8&!@8$!`0$!`0$!5
XM`0$!`0$!`0$!`0$!`1`0$!`0$(*"@H*"@@("`@("`@("`@("`@("`@("`@("A
X@$!`0$"````````/L`````0````(```"4`````````_("=
X``
Xend
Xsize 6692
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit