Esempio n. 1
0
IFile& IFile::getline(std::string &str){
  char tmp=0;
  str="";
// I comment out this (see note below on commented fgetpos):
// fpos_t pos;
// fgetpos(fp,&pos);
  while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err){
    str+=tmp;
  }
  if(tmp=='\r'){
    llread(&tmp,1);
    plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
  }
  if(eof){
    if(str.length()>0) eof=false;
  } else if(err || tmp!='\n'){
    eof = true;
    str="";
// there was a fsetpos here that apparently is not necessary
//  fsetpos(fp,&pos);
// I think it was necessary to have rewind working correctly
// after end of file. Since rewind is not used now anywhere,
// it should be ok not to reset position.
// This is necessary so that eof works properly for emacs files
// with no endline at end of file.
  }
  return *this;
}
Esempio n. 2
0
int getControlPacket(int port, ControlPacket* packet){
	unsigned char* buffer;
	int length = llread(port, &buffer);



	if(length < 0){
		free(buffer);
		return E_GENERIC;
	}
	if (buffer[0] != 1 && buffer[0] != 2){
		free(buffer);
		return E_NOTCONTROL;
	}

	packet-> end = buffer[0];
	int k;
	for(	k=0;k<length;k++){
		//printf("0x%02x, %x\n",k,buffer[k]);
	}

	int size;
	memcpy(&size, buffer+3, 4);
	packet->size = size;
	int filenameLength = buffer[8];
	packet->filename = malloc(filenameLength+1);
	int i;
	for(i=0;i<filenameLength+1;i++){
		packet->filename[i] = buffer[8+i];
		//printf("%c", buffer[8+i]);
	}
	//puts("");
	free(buffer);
	return length;
}
Esempio n. 3
0
int getDataPacket(int port, DataPacket* packet){
	unsigned char* buffer;
	int length = llread(port, &buffer);
	if (length < 1){
		free(buffer);
		return E_GENERIC;
	}



	if(buffer[0] != DATA_PACKET && buffer[0] == CONTROL_PACKET_END){
		//printf("lalalalala %02x lalala\n", buffer[0]);
		free(buffer);
		return E_NOTDATA;

	}
	packet->sequenceNumber = buffer[1];
	packet->size = 0x00;
	packet->size+= buffer[3];
	packet->size+= buffer[2]*256;
	//printf("%d packet size\n", packet->size);	
	packet->data = (char*) malloc(packet->size);
	memcpy(packet->data, buffer+4, packet->size);
	free(buffer);
	return length;
}
Esempio n. 4
0
int main (int argc, char** argv) {
	int txrx;
	
	
	linkLayer.fd = config(argv[1]);
	//write(linkLayer.fd, "ola", 3);
	printf("Reciver - 0\nTransmitter -1\n");
	scanf("%d", &txrx);
	
	printf("[MAIN] Opening llopen with %d\n", txrx);
	llopen(linkLayer.fd, txrx);
	printf("[MAIN] LLOPEN SUCCESFULL\n");
	
	if(txrx == TRANSMITTER)
	{
		unsigned char buffer[256] = "Eu Sou o jose delfim ribeiro valverdeasdasdasdasdasfasfsadfasdasdasdsafsdfasdfsadas ";
		llwrite(linkLayer.fd, buffer, 60);
	}
	else
	{
		char buffer[3];
		llread(fd,buffer);
		puts(buffer);
	}
	
	return 1;
}
Esempio n. 5
0
//******** cnopen *********************
//mode: FD_READ/FD_WRITE
int16_t cnopen(dir_ptr* dir, const char* name, uint8_t mode)
{
	stat_st stat_buf;
	if(cnstat(dir,name,&stat_buf) != 0)
	{
		if(mode == FD_WRITE) {
			check(cncreat(dir,name) == 0, "Could not create %s", name);
		}
		check(cnstat(dir,name,&stat_buf) == 0, "Could not stat %s", name);
	}
	//TODO: The fd bitmap is not 1 block long, hope we don't run out of fds
	int16_t fd = (int16_t)(uint16_t)find_free_bit((block*)fd_bm);
	set_bitmap((block*)fd_bm, fd);
	fd_tbl[fd].cursor = 0;
	fd_tbl[fd].state = mode;
	fd_tbl[fd].inode_id = stat_buf.inode_id;
	inode_read(stat_buf.inode_id, &fd_tbl[fd].inode);

	if(fd_tbl[fd].inode.blocks > 0)
	{
		fd_tbl[fd].data = calloc(fd_tbl[fd].inode.blocks,sizeof(block));
		llread(&fd_tbl[fd].inode, fd_tbl[fd].data);
	}
	else
	{
		fd_tbl[fd].data = NULL;
	}
	return fd;

error:
	return -1;
}
Esempio n. 6
0
int main(int argc, char** argv)
{
    int fd, res;
    struct termios oldtio,newtio;
	unsigned char * buffer;
	unsigned char UA[UALENGT]; 

    if ( (argc < 2) || 
  	     ((strcmp("/dev/ttyS0", argv[1])!=0) && 
  	      (strcmp("/dev/ttyS1", argv[1])!=0) )) {
      printf("Usage:\tnserial SerialPort\n\tex: nserial /dev/ttyS1\n");
      exit(1);
    }

      
    fd = open(argv[1], O_RDWR | O_NOCTTY );
    if (fd <0) {perror(argv[1]); exit(-1); }

    tcgetattr(fd,&oldtio); /* save current port settings */

    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;

    /* set input mode (non-canonical, no echo,...) */
    newtio.c_lflag = 0;

    newtio.c_cc[VTIME]    = 0.1;   /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 0;   /* blocking read until 1 chars received */

    tcflush(fd, TCIFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);

    printf("New termios structure set\n");

	res = llread(fd, buffer);
	
	if(res < 0)
	{
		printf("Error recieving msg!");
		exit(1);
	}

	UA[0] = F;
	UA[1] = A;
	UA[2] = 0x08;
	UA[3] = F;
	UA[4] = A;
	UA[5] = Cr;
	UA[6] = A^Cr;
	UA[7] = F;	

	res = llwrite(fd,UA, UALENGT);

    tcsetattr(fd,TCSANOW,&oldtio);
    close(fd);
    return 0;
}
Esempio n. 7
0
//******** inflatedir *****************
//Populates a dir_ptr from an iptr
void inflatedir(dir_ptr* dir, iptr inode_id)
{
	inode_read(inode_id,&dir->inode_st);
	dir->inode_id = inode_id;
	//Read the directory file for this inode
	dir->data = calloc(dir->inode_st.blocks, sizeof(block));  	//Memory for all directory file blocks
	llread(&dir->inode_st, dir->data);	//Read the directory file
	dir->index = 0;
}
Esempio n. 8
0
int appRead(char * port, char * filename) {
    printf("[appSend] Connecting to Sender...n");
    if(llopen(port, RECEIVER) < 0)
        return -1;

    char packet[256];
    pingu.size = 0;
    int psize = 0;
    int tsize = 0;



    printf("[appRead] CONNECTEDn");

    do {
        if(llread(packet)!=-1) {

            if(checkPacket(packet, &psize) != 0) {
                printf("[appRead] Unrecognized packet typen");
                return -1;
            }
            else {
                if(appDef.control == START_PAC) {
                    FILE *p = fopen(filename, "wb");
                    if( p < 0 ) {
                        printf("[appRead] Error opening output filen");
                        return -1;
                    }
                    pingu.p = p;
                }
                else if(appDef.control == DATA_PAC) {
                    fwrite(packet+4, sizeof(char), psize, pingu.p);
                    tsize += psize;
                }
                else if(appDef.control == END_PAC) {
                    //
                    break;
                }
            }

        }
    } while((pingu.size != tsize) || (appDef.control != END_PAC));

    printf("[appRead] Bytes read: [ %d / %d ]n", tsize, pingu.size);

    printf("[appRead] Closing connection...n");

    llclose(appDef.status);
    printf("[appSend] Exiting Application!n");

    return 0;
}
Esempio n. 9
0
int testread()
{
	char *receive;
	int rec_size = llread(app.fd, &receive);
	
	//catch info
	//char endchar = receive[rec_size - 1];
	//receive[rec_size - 1] = 0;
	printf("\n");
	//printf("%s%c - %d", receive, endchar, rec_size);test string
	int i=0;
	for(;i<rec_size;++i)
	printf(PRINTBYTETOBINARY " - " , BYTETOBINARY(receive[i]));
	printf("%d",rec_size);
	//gets(receive);
	if (rec_size>0)free(receive);

	//catch DISC
	rec_size = llread(app.fd, &receive);
	if (rec_size == -2) printf("\ngot disk");

	return 0;
}
//Recebe o DISC, responde DISC e recebe o UA
void terminacao(fd){
	char* buffer[255];

	char next = FALSE, isValid=TRUE;
	while(next!=TRUE){
		if(isValid==TRUE){
			printf("Comando recebido (DISC)\n");
			writeDISC(fd);
		}
		next = checkUA(buffer);
		if(next!=TRUE){
			llread(fd,buffer);
			isValid = checkDISC(buffer);
		}
	}
	printf("Comando recebido (UA)\n");
}
//Recebe o SET e responde UA
void estabelecimento(int fd, unsigned char* buffer)
{
	int res;
	int isValid = FALSE, next = FALSE, canProceed = FALSE;
	while(canProceed != TRUE || next!=TRUE)
	{
		res = llread(fd,buffer);
		isValid = checkSET(buffer);
		if(isValid==TRUE)
		{
			printf("Comando recebido (SET)\n");
			canProceed=TRUE;
			writeUA(fd);
		}
		else
		{
			next = checkFirstI(buffer);
		}
	}
}
Esempio n. 12
0
int readFile(int port)
{
	ControlPacket packet;
	while(!getControlPacket(port, &packet)){}
	//puts("\nGot beginning packet");
	if(packet.end != CONTROL_PACKET_BEGIN){
		printf("Error: didn't receive expected start control package\n");
		return -1;
	}

	int file = open(packet.filename+1, O_CREAT|O_TRUNC|O_WRONLY, 0666);
	free(packet.filename);
	DataPacket dataPacket;
	unsigned char expectedSequenceNumber = 0;
	float percentage;
	int acum = 0;
	char * proBar = updateProgressBar(0, packet.size, &percentage);
	while(getDataPacket(port, &dataPacket) != E_NOTDATA){

		if (expectedSequenceNumber != dataPacket.sequenceNumber){
			printf("Error in packet sequence: expected packet no %u and got packet no %u\n", expectedSequenceNumber, dataPacket.sequenceNumber);
		exit(-1);
		}
		expectedSequenceNumber++;
		expectedSequenceNumber %= 255;
		
		//printf("Received data packet with size %d\n", dataPacket.size);
		write(file, dataPacket.data, dataPacket.size);
		acum += dataPacket.size;
		proBar = updateProgressBar(acum, packet.size, &percentage);
		if(visMode != 0)
			printProgressBar(proBar, percentage);
		free(dataPacket.data);

	}
	printf("\n");
	unsigned char* dump;
	while(llread(port, &dump) != E_CLOSED){}	
	//puts("discei");
	return 0;
}
Esempio n. 13
0
//return 0 if ok, -1 if image was not received, -2 start faled, -3 if connection failed on disk
int receiveImage(bool reconnect) {

	//receive
	int ret = 0;
	if (reconnect == FALSE) image_already_bytes = 0;
	ret = receiveFile(app.fd, image_name, &image_bytes, &image_bytes_length, &image_already_bytes);

	if (ret == -1) can_reconect = YES;
	else can_reconect = NO;

	//receive disk(do this before saving image to avoid delays)
	char* packet; int llread_result = 0;
	llread_result = llread(app.fd, &packet);
	if (llread_result != -2)//read returns -2 when receives disk
	{
		if (llread_result > 0) free(packet);
		ret = -3;
	}

	return ret;
}
Esempio n. 14
0
//******** mkdir ********************
int8_t cnmkdir(const char* name)
{
	char* name_copy = strdup(name);
	char name_tok[256];
	char entry_name[256];
	char* next_name_tok;
	dir_entry* entry;
	dir_ptr *dir = calloc(1,sizeof(dir_ptr));		//Directory file in memory (e.g. DIR object from filedef.h)
	bool last_dir = false;

	inode_read(cwd->inode_id, &dir->inode_st);		//Start at cwd
	dir->inode_id = cwd->inode_id;

	next_name_tok = strtok(name_copy, "/");
	do
	{
		//name_tok is the dir we are searching for or going to create
		strcpy(name_tok, next_name_tok);

		//Read the directory file for this inode
		dir->data = calloc(dir->inode_st.blocks,sizeof(block));  	//Memory for all directory file blocks
		llread(&dir->inode_st, dir->data);	//Read the directory file
		dir->index = 0;

		next_name_tok = strtok(NULL, "/");		//Read the next token
		if(next_name_tok == NULL)   //This is the last directory in the path
		{
			last_dir = true;
		}

		//Find the token in this dir
		while((entry = cnreaddir(dir)))
		{
			memcpy(entry_name, entry->name, entry->name_len);
			entry_name[entry->name_len] = 0;
			if(strcmp(entry_name, name_tok) == 0)  //If this directory already exists
			{
				if(last_dir)
				{
					return -1;   //Directory already exists
				}
				else   //Read the directory inode
				{
					dir->inode_id = entry->inode;
					inode_read(entry->inode,&dir->inode_st);   //Read the next directory's inode
					free(dir->data);  //Forget the directory we just read
					break;
				}
			}
		}

		if(last_dir)  //Create the directory at the end of the list
		{
			//Create parent directory entry
			entry = (dir_entry*)(((uint8_t*)dir->data)+dir->index);
			entry->file_type = ITYPE_DIR;
			entry->inode = reserve_inode();
			memcpy(entry->name,name_tok,strlen(name_tok));
			entry->name_len = strlen(name_tok);
			entry->entry_len = entry->name_len + 8;
			entry->entry_len += (4 - entry->entry_len % 4);  //padding out to 32 bits
			dir->inode_st.size += entry->entry_len;
			//TODO: handle mkdir block overflow

			//Write parent dir and inode
			dir->inode_st.modified = time(NULL);
			inode_write(dir->inode_id, &dir->inode_st);
			blk_write(dir->inode_st.data0[0], dir->data);

			//Write new directory inode
			inode new_dir_i;
			memset(&new_dir_i, 0, sizeof(inode));
			uint32_t now = time(NULL);
			new_dir_i.modified = now;
			new_dir_i.type = ITYPE_DIR;
			new_dir_i.size = 0;
			new_dir_i.blocks = 1;
			new_dir_i.data0[0] = reserve_block();

			//Write new directory file
			block* new_dir_block = calloc(1,sizeof(block));

			// . (self entry)
			dir_entry* new_dir_self_entry = (dir_entry*)new_dir_block;
			new_dir_self_entry->inode = entry->inode;
			new_dir_self_entry->file_type = ITYPE_DIR;
			new_dir_self_entry->name_len = 1;
			new_dir_self_entry->entry_len = 12;
			memcpy(new_dir_self_entry->name, ".", 1);
			new_dir_i.size += 12;

			// .. (parent entry)
			dir_entry* new_dir_parent_entry = (dir_entry*)(((uint8_t*)new_dir_block) + 12);
			new_dir_parent_entry->inode = dir->inode_id;
			new_dir_parent_entry->file_type = ITYPE_DIR;
			new_dir_parent_entry->name_len = 2;
			new_dir_parent_entry->entry_len = 12;
			memcpy(new_dir_parent_entry->name, "..", 2);
			new_dir_i.size += 12;

			//Write new dir and inode
			inode_write(entry->inode, &new_dir_i);
			blk_write(new_dir_i.data0[0], new_dir_block);

			free(new_dir_block);
			break;
		}

	} while(1);
	free(dir);
	free(name_copy);
	return 0;
}
Esempio n. 15
0
int main (int argc, char ** argv) {
    ll.baudRate = 9600;
    ll.timeout = 1;
    ll.numTransmissions = 3;

    int port = 0;
    int flag = 0;
    int read_ret = 0;

    if (argc < 3) {
        printf("Usage:\t./app PortNumber flag\n\tex: ./app 5 1\n");
        exit(1);
    }

    port = atoi(argv[1]);
    flag = atoi(argv[2]);

    if(port > 5 || port < 0) {
        printf("Port number must be between 0 and 5!\n");
        exit(1);
    }

    if(flag != 0 && flag != 1) {
        printf("Flag must be 0 or 1!\n");
        exit(1);
    }

    if(flag==0) {
        printf("Write the name of the file you want to copy: ");
        strcpy(ctrData.filePath,"");
        gets(ctrData.filePath);
        ctrData.fpLength = strlen(ctrData.filePath);
    }

    char sPort[20];

    strcpy(sPort,"");
    sprintf(sPort, "/dev/ttyS%d",port);

    appLayer.status = flag;
    strcpy(ll.port,sPort);

    if(flag == 0)
        if(readData() != 0) {
            printf("\nError: File doesn't exist!\n\n");
            return -1;
        }

    if(llopen() == -1) {
        printf("Error llopen!\n");
        exit(1);
    }

    if(appLayer.status == 0) {
        if(create_packets_send() == -1) {
            printf("Error llwrite!\n");
            exit(1);
        }
    }
    else {
        int control = 0;
        while(TRUE) {
            read_ret = llread(control);

            if (read_ret == 1) {
                checkControl(read_ret-1);
                control = 1;
            }
            else if(read_ret == 2) {
                checkControl(read_ret-1);
            }
            else if(read_ret == 3) {
                if(llclose() != 0) {
                    printf("\n\nError: llclose()!\n\n");
                    exit(-1);
                }
            }
        }
    }

    llclose();

    return 0;
}
Esempio n. 16
0
int app_read(char * port) {

	printf("> [APP] Connecting...\n");

	int fd = llopen(port, RECEIVER);
	
	if(fd < 0) {
		return ERROR;
	}
	
	char packet[MAX_FRAME_SIZE];
	fstatus.size = 0;
	fstatus.valid = FALSE;
	int fsize = 0;
	
	printf("> [APP] Connection established...\n");

	printf("> [APP] Receiving...\n");

	do{
		int size = llread(&packet[0]);
		
		if(size == -2) { // Disconnect (forced)
			break;
		}
		else if(size < 0) {
			printf("  > [APP] Some error ocurred reading a packet. Exiting...\n");
			return ERROR;
		}
		else {
			if(app_check_packet(packet, size) != OK){
					printf("  > [APP] Unrecognized packet type\n");
					return ERROR;
			}
			else {
				if(pack.ctrl == PACKET_START) {
					FILE *f = fopen(((fstatus.name == NULL) ? "out" : fstatus.name), "w");
					if( f < 0 ) {	
						printf("> [APP] Error opening output file\n");
						return ERROR;
					}
					fstatus.f = f;
					
					fstatus.valid = TRUE;
				}
				else if(fstatus.valid != TRUE) {
					printf("> [APP] No file info received\n");
					return ERROR;
				}
				else if(pack.ctrl == PACKET_DATA) {
					//writing data to file 
					fwrite(pack.data.buf, sizeof(char), pack.data.length, fstatus.f);
					fsize += pack.data.length;
				}
				else if(pack.ctrl == PACKET_END) {
					//
					break;
				}
			}
		}

	} while((fstatus.size != fsize) || (pack.ctrl != PACKET_END));
	
	printf("> [APP] Bytes read: [ %d / %d ]\n", fsize, fstatus.size);
	
	printf("> [APP] Closing connection...\n");
	
	llclose();

	return OK;
}
Esempio n. 17
0
int receivePacket(int fd, char **packet, int *sizePacket) {
	*sizePacket = llread(fd, packet);
	if (*sizePacket > 0) return OK;
	//else if (*sizePacket == -2) return -2;/*received disk*/
	else return -1;
}
Esempio n. 18
0
int llread(int fd, unsigned char **buffer){
	//printf("preparing to read frame\n");
	Command command = receiveCommand(fd);
	//puts("llread:received command");
	int repeated;
	if (command.command == I(ll.sequenceNumber))
		repeated = 0;
	else if (command.command == I(!ll.sequenceNumber))
		repeated = 1;
	else if (command.command == DISC){
			//printf("llread: disconnecting\n");
			while(!sendByte(fd, 0x01, DISC)){}
			//puts("llread: disc confirmation sent\n");
			command = receiveCommand(fd);
			if (command.command != UA){
				//puts("llread: didnt receive UA after disc confirmation\n");
				return E_GENERIC;
			}
			else{
				//puts("llread: connection successfully closed\n");
				return E_CLOSED;
			}
	}

	if (command.command == I(0) || command.command == I(1)){
		//puts("llread: received a data frame\n");
		//if we never saw this frame before, consider it
		stats.dataFramesTransmitted++;
		if(!repeated){
			//puts("llread: new data frame\n");
			int length = byteDeStuffing(&(command.data), command.size);
			//puts("llread: destuffing succeeded\n");
			int bccOK = verifyBCC(command.data, length, command.data[length-1]);

			if(getRand() < RANDOM_REJ_CHANCE){
				bccOK = 0;
			//	puts("\n randomly rejecting good packet");
			}

			//Reject frames with wrong BCC
			if(!bccOK){
				//puts("llread: frame was damaged, rejecting and rereading\n");
				stats.rejs++;
				while(!sendByte(fd, 0x03, REJ(ll.sequenceNumber) )){}
					return llread(fd, buffer);

			}

			//accept the frame and confirm it
			//puts("llread: frame bcc ok, accepting\n");
			*buffer = (unsigned char*) malloc(length);
			memcpy(*buffer, command.data, length);
			while(!sendByte(fd,0x03, RR(!ll.sequenceNumber))){}
			//puts("llread: receiver ready sent, message confirmed\n");
			ll.sequenceNumber = !ll.sequenceNumber;
			free(command.data);
			//printf("%d length\n", length);
			return length;

		}
		//this frame is repeated. Confirm it and ask for the new frame
		else{
				//puts("llread: message repeated");
				while(!sendByte(fd, 0x03, RR(ll.sequenceNumber))){}
				return E_GENERIC;
		}

	}

	else{
		//printf("received unexpected command 0x%02x\n",command.command);
		return E_GENERIC;
	}

	return 0;


}
//Recebe as tramas de dados e responde RR
int transfDados(int fd, char* buffer, char* data, int filesize)
{
	char dados[15000];
	int res=0,i, a=0;
	int pointer=0;
	char nr,cns,cnr;
	nr=0x0;
	cns=0x0;
	cnr=0x5;
	int isValid = FALSE, next = FALSE;

	while(next!=TRUE)
	{
		isValid = checkI(buffer,cns);

		if(isValid==TRUE)
		{
			getData(buffer,data);
			if (data[0]==1)
			{
				printf("Recebida trama de controlo de dados (start)\n");
				char fsize[data[2]];
				while(a<data[2])
				{
					fsize[a]=data[a+3];
					a++;
				}
				filesize = atoi(fsize);
				a=0;
				while(a<=data[4+data[2]])
				{
					filename[a]=data[4+data[2]+a];
					//printf("%c",filename[a]);
					a++;
				}
				filename[a]='\0';
			}
			else if(data[0]==0)
			{
				pointer = lerdados(data,dados,pointer);
				printf("A escrever dados na posicao %d de um total de %d\n",pointer,filesize);
			}
			else if(data[0]==2)
			{
				printf("Recebida trama de controlo de dados (end)\n");
				/*if(filesize!=(data[3]))
				{
					printf("Dados corrompidos, tamanho do ficheiro nao e valido.%d\n",data[3]);
					exit(1);
				}
				if(filename!=data[6])
				{
					printf("Dados corrompidos. Impossivel terminar.\n");
					exit(1);
				}*/
			}
			else
			{
				printf("Trama de dados corrompida.\n");
			}
			//Verifica o valor do N(r) anterior para o poder alterar
			if(nr==0x1){
				nr=0x0;
				cns=0x0;
				cnr=0x5;
			}
			else{
				nr=0x1;
				cns=0x2;
				cnr=0x25;
			}
			writeRR(fd,cnr);//Escreve o RR de resposta que permite ao Sender identificar se enviou o I bem ou necessita de enviar outra vez
		}
		else
		{

			next = checkDISC(buffer);
			if(next==FALSE)
			{
				writeRR(fd,cnr);
			}
			else{
				for(i=0; i<filesize; i++){
					data[i] = dados[i];
				}
				return filesize;
			}
		}
		llread(fd,buffer);
	}
}