home *** CD-ROM | disk | FTP | other *** search
- /*
- kv - removes the IRQ virus from an executable file.
- compile with Manx C - 16 bit mode ok
-
- Routine IRQ_Kill() does the work, the rest is a vehicle
-
- This program will also detect one varient of the Lamer virus in memory
- and deactivate it.
-
- Also checks for the BGS9 virus
-
- Djj 8/25/89
- */
- #include <exec/types.h>
- #include <exec/exec.h>
- #include <libraries/dos.h>
- #include <intuition/intuition.h>
- #include <devices/trackdisk.h>
- #include <exec/execbase.h>
- #include <exec/resident.h>
- #include <stdio.h>
-
-
- #define VERSION "KV ver 2.0 09/01/89 Djj"
-
- #define VTAG 0x00000109L /* virus hunk length */
- #define VSIG1 0x0000FFFEL /* part of virus signature */
- #define VSIG2 0x61000000L /* part of virus signature */
-
- #define BEGIN OFFSET_BEGINNING
- #define END OFFSET_END
- #define OLD MODE_OLDFILE
- #define NEW MODE_NEWFILE
-
- #define SLONG ((long)(sizeof(long)))
-
- #define OK 1 /* no error */
-
- #define NOFILE -1 /* can't find file */
- #define SEEKERR -2 /* seek error on file */
- #define ALLOCERR -3 /* can't allocate memory */
- #define READERR -4 /* error reading file */
- #define VIRUSNF -5 /* virus not found in file */
- #define WRITERR -6 /* error writing to file */
- #define OPENERR -7 /* error opening file for write */
- #define NOTEXE -8 /* not an executable file */
-
- #define DEADXENO -9 /* disabled XENO found */
- #define GOTHIM OK /* removed virus from file */
-
- static UBYTE txt[40];
- static long inp, *buff, size;
- extern long Open(), Seek(), Read(), Write(), *AllocMem();
- long DOSBase, IntuitionBase, OpenLibrary();
-
- int Xeno = FALSE;
-
- struct IntuiText Msg3 = { 3, 1, JAM2, 10, 30, 0,(UBYTE*)NULL, NULL };
- struct IntuiText Msg2 = { 2, 1, JAM2, 10, 20, 0,(UBYTE*)NULL, &Msg3 };
- struct IntuiText Msg1 = { 2, 1, JAM2, 10, 10, 0,(UBYTE*)NULL, &Msg2 };
-
- struct IntuiText OKText = { 3, 1, JAM2, 6, 3, 0,(UBYTE*)" OK ", NULL };
-
-
- main(argc,argv)
- char **argv;
- {
- static char opts[] = "aAiIbBlL", *strchr();
- char *posn, *temp;
- int lamer = 0, irq = 0, bgs = 0, cnt = 1;
- int indx, i, args;
-
-
- if(argc < 2)
- usage(argv[0]);
-
- IntuitionBase = OpenLibrary("intuition.library",0L);
- DOSBase = OpenLibrary("dos.library",0L);
-
- args = argc;
- for(i = 1; i < argc; i++)
- {
- temp = argv[ i ];
- if(*temp == '?')
- usage();
- if(*temp++ == '-')
- {
- args--;
- while(*temp)
- {
- if((posn = strchr(opts,*temp)) == 0)
- {
- printf("Unknown option %c\n",*temp++);
- continue;
- }
- indx = posn - opts;
- switch(indx)
- {
- case 2: case 3:
- irq = 1; temp++;
- break;
- case 4: case 5:
- bgs = 1; temp++;
- break;
- case 6: case 7:
- lamer = 1; temp++;
- break;
- case 0: case 1:
- bgs = lamer = 1; temp++;
- break;
- }
- }
- }
- else
- {
- CheckIRQ(argv[i]);
- }
- }
-
-
- if(lamer)
- CheckLamer();
-
- if(bgs)
- Check_BGS9();
-
- exit(cleanup(1));
- }
-
- CheckIRQ(dev)
- char *dev;
- {
- int err;
- char *pat = 0, *name = 0, *scdir(), *malloc(), ch;
- /*
- scan argument list for filenames. Use each name as input to the
- wildcard expander. If a name ends with `:' or `/' then it's a
- device or directory. As a favor to the user, append the wildcard
- `*' character to the end of that name.
- */
- printf("Checking for IRQ and Xeno virus on %s\n",dev);
- if(pat) free(pat);
- pat = malloc(strlen(dev)+1); /* leave room for `*' if needed */
-
- if(pat == 0)
- {
- puts("Out of memory");
- exit(cleanup(20));
- }
- strcpy(pat,dev); /* get filename from command line */
-
- ch = pat[ strlen(pat)-1 ];
- if(ch == ':' || ch == '/')
- strcat(pat,"*");
-
- /*
- do this until no more names can be squeezed out of this argument
- */
- while(1)
- {
- if((name = scdir(pat)) == NULL)
- break;
- err = IRQ_Kill(name); /* check for and possibly remove virus */
-
- switch(err)
- {
- case GOTHIM:
- printf("\2337m");
- printf("Found and disabled the %s virus in \"%s\"!\n",
- (Xeno) ? "XENO" : "IRQ", name);
- printf("\2330m");
-
- if(!Xeno)
- {
- DisplayBeep(0L);
- Msg1.IText = (UBYTE *)"Found the IRQ virus in file";
- Msg3.IText = (UBYTE *)"IRQ virus removed";
- }
- else
- {
- Msg1.IText = (UBYTE *)"Found the XENO virus in file";
- Msg3.IText = (UBYTE *)"XENO virus disabled";
- }
- Msg2.IText = txt;
- sprintf(txt," %s",name);
-
- if(!Xeno)
- putmsg();
- else
- Delay(20L);
- break;
- case NOFILE: printf("\tcan't find \"%s\"\n",name);
- break;
- case SEEKERR: printf("\tseek error on \"%s\"\n",name);
- break;
- case ALLOCERR: printf("\tcan't allocate memory\n");
- break;
- case READERR: printf("\terror reading \"%s\"\n",name);
- break;
- case VIRUSNF: printf("\"%s\" was OK\n",name);
- break;
- case WRITERR: printf("\terror writing to \"%s\"\n",name);
- printf("\tFile \"%s\" is corrupt...replace it\n",name);
- break;
- case OPENERR: printf("\terror opening \"%s\" for write\n",name);
- break;
- case NOTEXE: printf("\t\"%s\" is not an executable file\n",name);
- break;
- case DEADXENO: printf("found disabled XENO virus in \"%s\"\n",name);
- }
- }
- }
-
- CheckLamer()
- {
- puts("Checking for Lamer virus");
- Check_Memory_Lamer();
- Check_Disk_Lamer();
- }
-
- cleanup(val)
- int val;
- {
- if(inp)
- {
- Close(inp);
- inp = 0;
- }
- if(buff)
- {
- FreeMem(buff,size);
- buff = 0;
- }
- return val;
- }
-
-
- IRQ_Kill(fname)
- char *fname;
- {
- int i = 0;
- long fhunk, lhunk, nhunk, val, len;
-
- inp = 0L; buff = 0L;
-
- if((inp = Open(fname,OLD)) == 0) /* open the desired file */
- return NOFILE;
-
- Read(inp,&val,SLONG); /* get the first long word */
- if(val != 0x000003F3L) /* check for executable file */
- return cleanup(NOTEXE);
-
- Seek(inp,0L,END); /* seek to end of file */
- size = Seek(inp,0L,BEGIN); /* rewind the file to get size */
- if(size <= 0L)
- return cleanup(SEEKERR);
-
- if((buff = AllocMem(size,0L)) == 0) /* mem buffer for file */
- return cleanup(ALLOCERR);
-
- if(Read(inp,buff,size) != size) /* read entire file into buffer */
- return cleanup(READERR);
-
- nhunk = buff[ 2 ]; /* number of hunks in file */
- fhunk = buff[ 3 ]; /* first hunk */
- lhunk = buff[ 4 ]; /* last hunk */
-
- /*
- the IRQ virus inserts his code as the first hunk in the file
- we can find the first hunk in the 6th longword of the file
- */
- /* find the start of the virus hunk */
- i = 5 + lhunk - fhunk + 1;
-
- Xeno = FALSE;
-
- if(buff[5] != VTAG)
- {
- if(buff[ i + 0x116 ] != 'astf')
- return cleanup(VIRUSNF);
- else
- {
- Xeno = TRUE;
- if(buff[i+2] == 0x60000462)
- return cleanup(DEADXENO);
- }
- }
-
- /*
- The virus checks the first hunk for it's signature to prevent
- reinfecting an already infected program. It actually checks for
- 0xFFFE6100 which is the lower half of a move.m instruction and
- the upper half of a bsr instruction. Here we do the same.
- i points to the virus code hunk length.
- */
- if(!Xeno)
- if( ((buff[ i+2 ] & 0x0000FFFF) != VSIG1)
- || ((buff[ i+3 ] & 0xFFFF0000) != VSIG2) )
- return cleanup(VIRUSNF);
-
- /*
- close the file and reopen it with write access
- mode NEW will effectivly delete the old file contents so if a
- file error occurs before we finish, the file will be corrupt
- */
- Close(inp); inp = 0;
-
- if((inp = Open(fname,NEW)) == 0)
- return cleanup(OPENERR);
-
- if(!Xeno) /* readjust program header info */
- {
- buff[2] -= 1;
- buff[4] -= 1;
- /* write new header */
- if(Write(inp,buff,5L*SLONG) != 5L*SLONG)
- return cleanup(WRITERR);
-
- if(Write(inp,&buff[6],nhunk*SLONG) != nhunk*SLONG)
- return cleanup(WRITERR);
-
- /*
- subtract length of virus hunk and overhead from file size
- i was calculated earlier
- */
- i = i + 9L + VTAG;
- size = (size/SLONG - i)*SLONG;
-
- /* and write old code out to file, ignoring virus hunk */
- if(Write(inp,&buff[i],size) != size)
- return cleanup(WRITERR);
-
- /* we're done, the file is clean and intact */
- return cleanup(GOTHIM);
- }
- else /* Xeno virus */
- {
- buff[i+2] = 0x60000462;
-
- /* now fix the code segment length and write it out */
-
- if(Write(inp,buff,size) != size)
- return cleanup(WRITERR);
-
- /* we're done, the file is clean and intact */
- return cleanup(GOTHIM);
- }
- }
-
- usage(name)
- char *name;
- {
- printf("%s\n\n",VERSION);
- printf("%s will detect and remove one type of `Lamer' and `BGS' virus \n",name);
- printf("from all floppies in the system. It will also detect and remove\n");
- printf("IRQ virus V41.0 from executable files and detect and disable the\n");
- printf("XENO virus in executable files\n\n");
- printf("Usage: %s -LIBA { filename ... }\n\n",name);
- printf("\t-L or -l check for Lamer virus on all floppies\n");
- printf("\t-B or -b check for BGS-9 virus on all floppies\n");
- printf("\t-I or -i NAME check for IRQ and Xeno virus on NAME\n");
- printf("\t-A or -a do all of the above\n\n");
- printf("\t`*' (unix style) wildcards allowed\n");
- printf("\tex. %s -i C:* or %s -i C: will check all files in C:\n",
- name,name);
- printf("\t\tfor the IRQ and Xeno virus\n");
- printf("\t %s DF0:C/ will check all files in DF0:C\n",name);
- exit(cleanup(20));
- }
-
- #define LAMER_ID "clist 33.80"
-
- Check_Memory_Lamer()
- {
- struct ExecBase **ExecPtr = 4;
- APTR *KTagPtr = (APTR *)(*ExecPtr)->KickTagPtr;
- APTR Lamer, TestKTag();
-
- while(*KTagPtr)
- {
- /*
- If hi bit is set, then this is a pointer to a KickTag array. Reset
- the bit and use the resulting address to get the address of the
- next KickTag array.
- */
- while((ULONG)*KTagPtr & 0x80000000)
- KTagPtr = (APTR *)((ULONG)*KTagPtr & 0x7FFFFFFF);
-
- /*
- if the Lamer is found, invalidate the KickTag element here by
- changing the KickTag element to a pointer to a KickTag array which
- points to the next element. A cheap shot, but effective
- */
- if(Lamer = TestKTag( *KTagPtr ))
- {
- if(KillLamer(Lamer))
- {
- *KTagPtr = (APTR)((ULONG)(KTagPtr+1) | 0x80000000);
-
- SumKickData(); /* do the real SumKickData */
-
- Msg1.IText = txt;
- sprintf(txt,"Lamer virus found at %08lx",Lamer);
- putmsg();
- return;
- }
- }
- KTagPtr++;
- }
- }
-
- /*
- This is supposed to compute the correct Kick memory checksum to
- allow the users RAD: disk to recover on the next reboot.
- The SumKickData vector was recovered from the virus and reinstalled
- in the execbase structure by KillLamer()
- */
-
- SumKickData()
- {
- #asm
- move.l 4,a6
- jsr -$264(a6) ;calculate checksum
- move.l d0,$22A(a6) ;store it
- #endasm
- }
-
- KillLamer(addr)
- APTR addr;
- {
- #define RTS 0x70014E75 /* moveq.l #1,d0 rts */
- struct ExecBase **ExecPtr = 4;
-
- /*
- I think that the Lamer is in memory. I'm going to test several
- locations within the virus body to be sure that it is the exact
- virus I'm familiar with. The test array has memory offsets from
- addr and the contents I expect to see there.
- */
- static APTR test[] = {
- 0x0A6, 0x2F3A0EEC, /* SumKick routine */
- 0x166, 0x2F3A0E3C, /* DoIO routine */
- 0x246, 0x2F3A0D64, /* TDRead routine */
- 0x2B8, 0x287A0D0C, /* Trigger point */
- 0x5AE, 0x2C780004 /* Disk Trasher */
- };
-
- /*
- I'm going to pull the vipers fangs by placing RTS instructions in
- key areas. One area is his Resident Initialization vector - that'll
- stop him from living through a re-boot (provided he's not on the
- boot disk that is)
- */
- static APTR rts[] = {
- 0, /* Keep from initializing on reset */
- 0x2B8, /* disable one trigger point */
- 0x5AE, /* stop the disk trasher */
- 0x6D8, /* stop the alerts */
- 0x73C /* his ReBoot exit */
- };
-
- int i;
- APTR ptr;
- UBYTE *vec, *mem;
- ULONG *vect, FindName();
-
- for(i = 0; i < sizeof(test)/sizeof(ULONG); i+= 2)
- {
- ptr = addr+test[ i ];
- if( *ptr != test[ i+1 ] )
- {
- if(*ptr != RTS)
- {
- Msg2.IText = (UBYTE *)"I don't know this one";
- Msg3.IText = (UBYTE *)"virus NOT removed!";
- return 0;
- }
- else
- {
- Msg3.IText = (UBYTE *)"It's OK! It's been deactivated";
- return 0;
- }
- }
- }
- for(i = 0; i < sizeof(rts)/sizeof(ULONG); i++)
- {
- ptr = addr+rts[ i ];
- *ptr = RTS;
- }
-
- /*
- Get the SumKickData vector from the virus and reinstall it in the
- ExecBase jump table.
- */
- vec = (UBYTE *)(*ExecPtr);
- vect = (ULONG *)(vec - 0x264+2); /* ExecBase offset */
- ptr = addr+0x3E5; /* Offset from Lamer Init vector */
- *vect = (ULONG)*ptr; /* restore vector */
-
- /*
- Get the Trackdisk read vector from the virus and reinstall it
- */
- vect = (ULONG *)(FindName(&(*ExecPtr)->DeviceList,TD_NAME)-0x1c);
- ptr = addr + (0xFAC/4);
- *vect = (ULONG)*ptr;
-
- Msg3.IText = (UBYTE *)"Virus removed!";
- return 1;
- }
-
- /*
- Test the Resident structure ID string to see if it matches the one
- the Lamer uses. Return the structures Init vector if true, NULL if
- not
- */
- APTR TestKTag( res )
- struct Resident *res;
- {
- if(strncmp(LAMER_ID,res->rt_IdString,strlen(LAMER_ID)) == 0)
- return res->rt_Init;
- return (APTR)NULL;
- }
-
- struct Port *diskport = 0, *CreatePort();
- struct IOExtTD *diskreq = 0, *CreateExtIO();
-
- #define SEC_SIZE 512L
- #define ROOT 880L
- #define HASHCHAIN 124
- #define WRITE_PROTECTED -1
- #define NO_DISK -2
-
- UBYTE *diskdata = 0;
- UBYTE invisible[] = "DF0:\240\240\240\240\240";
- UBYTE newfile[] = "DF0:DANGERVIRUS";
-
- WriteBlock(block)
- long block;
- {
- LONG offset;
-
- MotorOn();
-
- offset = block * SEC_SIZE;
-
- diskreq->iotd_Req.io_Length = SEC_SIZE;
- diskreq->iotd_Req.io_Data = (APTR)diskdata;
- diskreq->iotd_Req.io_Command = CMD_WRITE;
- diskreq->iotd_Req.io_Offset = offset;
-
- DoIO(diskreq);
-
- if(diskreq->iotd_Req.io_Error != 0)
- printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
-
- diskreq->iotd_Req.io_Command = ETD_UPDATE;
- DoIO(diskreq);
-
- MotorOff();
- }
-
- ReadBlock(block)
- long block;
- {
- LONG offset;
-
- MotorOn();
-
- offset = block * SEC_SIZE;
-
- diskreq->iotd_Req.io_Length = SEC_SIZE;
- diskreq->iotd_Req.io_Data = (APTR)diskdata;
- diskreq->iotd_Req.io_Command = CMD_READ;
- diskreq->iotd_Req.io_Offset = offset;
-
- DoIO(diskreq);
-
- if(diskreq->iotd_Req.io_Error != 0)
- printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
-
- MotorOff();
- }
-
- MotorOn()
- {
- diskreq->iotd_Req.io_Length = 1;
- diskreq->iotd_Req.io_Command = TD_MOTOR;
- DoIO(diskreq);
- }
-
- MotorOff()
- {
- diskreq->iotd_Req.io_Length = 0;
- diskreq->iotd_Req.io_Command = TD_MOTOR;
- DoIO(diskreq);
- }
-
- CheckDOS()
- {
- ReadBlock(0L);
- if(diskdata[0] == 'D' && diskdata[1] == 'O' && diskdata[2] == 'S')
- return 1;
- return 0;
- }
-
- DiskStatus()
- {
- diskreq->iotd_Req.io_Flags = 0;
- diskreq->iotd_Req.io_Command = TD_PROTSTATUS;
-
- DoIO(diskreq);
-
- if(diskreq->iotd_Req.io_Error == TDERR_DiskChanged)
- return NO_DISK;
-
- if(diskreq->iotd_Req.io_Actual)
- return WRITE_PROTECTED;
-
- return OK;
- }
-
- Check_Disk_Lamer()
- {
- int i;
-
- for(i = 0; i < 4; i++)
- {
- if(OpenDiskResource(i) == 0)
- return;
-
- CheckDisk(i);
-
- CloseDiskResource();
- }
- }
-
- OpenDiskResource(num)
- int num;
- {
- struct ExecBase **ExecPtr = 4;
- ULONG td, FindName();
-
- td = FindName(&(*ExecPtr)->DeviceList,TD_NAME);
- diskdata = (UBYTE *)AllocMem(SEC_SIZE,(LONG)(MEMF_CHIP | MEMF_CLEAR));
-
- diskport = CreatePort(0L,0L);
- if(diskport == NULL || diskdata == NULL)
- exit(cleanup(20));
-
- diskreq = CreateExtIO(diskport,(long)sizeof(struct IOExtTD));
- if(diskreq == NULL)
- {
- DeletePort(diskport);
- exit(cleanup(20));
- }
-
- if(OpenDevice(TD_NAME,(LONG)num,diskreq,0L))
- return 0;
-
- return 1;
- }
-
- CloseDiskResource()
- {
- if(diskreq)
- {
- CloseDevice(diskreq);
- DeleteExtIO(diskreq,(long)sizeof(struct IOExtTD));
- DeletePort(diskport);
- }
-
- if(diskdata)
- FreeMem(diskdata,SEC_SIZE);
-
- diskreq = 0;
- diskdata = 0;
- }
-
- CheckDisk(num)
- int num;
- {
- int i;
- long *buff, Virus = 0, block, link = 0, before = 0, after = 0;
- unsigned long lock, Lock(), CheckSum();
- char drive[5];
-
- if(DiskStatus() == NO_DISK || CheckDOS() == 0)
- return;
-
- invisible[2] = newfile[2] = 0x30 + num;
-
- if((lock = Lock(invisible,ACCESS_READ)) == DOSFALSE)
- return;
- UnLock(lock);
-
- strncpy(drive,invisible,4); drive[4] = 0;
-
- if(DiskStatus() == WRITE_PROTECTED)
- {
- #ifdef CLI
- printf("CAUTION! Lamer Virus found on drive %4s\n",drive);
- printf("Disk is write protected. Make disk writable\n");
- #else
- Msg1.IText = txt;
- sprintf(txt,"Lamer Virus found on %4s",drive);
- Msg2.IText = (UBYTE *)"Disk is write protected";
- Msg3.IText = (UBYTE *)"Make disk writable";
- putmsg();
- #endif
- return;
- }
-
- if((lock = Lock(newfile,ACCESS_READ)) != DOSFALSE)
- {
- UnLock(lock);
- DeleteFile(newfile);
- }
-
- if(Rename(invisible,newfile) == DOSFALSE)
- {
- printf("WARNING - attempt to rename virus has failed\n");
- printf("The virus hides in an invisible file on drive %4s\n",drive);
- }
- else
- {
- printf("NOTICE! - Lamer virus found on drive %4s\n",drive);
- printf("The virus has been renamed to %4sDANGERVIRUS.\n",drive);
- printf("Please delete this file and edit your Startup-Sequence file\n");
- printf("to remove the invisible filename found on the first line\n");
- }
- /* virus is present */
- ReadBlock(ROOT);
-
- buff = (long *)diskdata;
-
- Virus = buff[ 15 ];
-
- for(i = 14; i > 6; i--)
- if(before = buff[ i ])
- break;
-
- if(before == 0)
- return;
-
- for(i = 16; i < 81; i++)
- if(after = buff[ i ])
- break;
-
- if(after == 0)
- return;
-
- block = before;
- do {
- ReadBlock(block);
-
- link = buff[ HASHCHAIN ];
-
- if(link == after)
- {
- buff[ HASHCHAIN ] = buff[ 5 ] = 0;
- buff[ 5 ] = CheckSum(buff);
- WriteBlock(block);
- break;
- }
- } while(block = link);
- }
-
- unsigned long CheckSum(block)
- unsigned long block[];
- {
- int cnt;
- unsigned long sum = 0;
- for(cnt = 0; cnt < 128; cnt++)
- sum += block[ cnt ];
- return (~sum + 1);
- }
-
- putmsg()
- {
- AutoRequest(NULL,&Msg1,NULL,&OKText,NULL,NULL,300L,80L);
- }
-
- UBYTE BGS_name[] = "DF0:devs/\240\240\240 \240 \240";
- UBYTE newname[] = "DF0:devs/OLD_PROGRAM.BGS9";
-
-
- Check_BGS9(num)
- {
- int i;
-
- puts("Checking for BGS virus");
-
- for(i = 0; i < 4; i++)
- {
- if(OpenDiskResource(i) == 0)
- return;
-
- CheckDiskBGS(i);
-
- CloseDiskResource();
- }
- }
-
- CheckDiskBGS(num)
- int num;
- {
- ULONG file;
- UBYTE drive[5];
- int i;
-
- if(DiskStatus() == NO_DISK || CheckDOS() == 0)
- return;
-
- BGS_name[2] = num + '0';
- if((file = Lock(BGS_name,ACCESS_READ)) != DOSFALSE)
- {
- UnLock(file);
- strncpy(drive,BGS_name,4); drive[4] = 0;
- sprintf(txt,"BGS virus found on %s",drive);
- Msg1.IText = txt;
-
- if(DiskStatus() == WRITE_PROTECTED)
- {
- Msg2.IText = (UBYTE *)"Disk is write protected";
- Msg3.IText = (UBYTE *)"Make disk writable";
- putmsg();
- CloseDiskResource();
- return;
- }
- newname[2] = num + '0';
- if(Rename(BGS_name,newname) == DOSFALSE)
- {
- Msg3.IText = (UBYTE *)"Rename failed";
- }
- putmsg();
-
- printf("You must now examine %sS/Startup-Sequence",drive);
- puts(" and note the name of the first");
- puts("executable file. That file contains the BGS virus\n");
- puts("DELETE that file and replace it with a know good copy");
- puts("You might also want to remove or rename the file located in");
- printf("%s/devs. It contains the original program replaced",drive);
- puts(" by the BGS virus");
- }
- }
-