Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: ANTÓN RAMIREZ en 13 Diciembre 2010, 04:17 am



Título: OPERACIONES BASICAS CON FILES
Publicado por: ANTÓN RAMIREZ en 13 Diciembre 2010, 04:17 am
hola a todos gracias por tu consejo Sagrini en realidad quisiera pedirte si me puedes brindar material de como empezar en linux , estoy muy implementado en dev y quiero tocar otras opciones , bueno en esta oportunidad te dejo un code sobre operaciones con files , compilalo con el dev-c++ y presiona F9 si gusta para compilar rapido .

AQUI podras apreciar aparte de las operaciones basicas como insertar registros , eliminar registros , mostrar registros , un actualizar con punteros , metodos de ordenamiento por codigo y por nombre es novedoso estos metodos , tambien hay varias decoraciones implemente algoritmos para capturar cuadros y hora -fecha del sistema este proyecto me costo muxo , quiero compartirlo con ustedes , haber Sagrini si das tu visto bueno a mi proyecto y como dices apoyame para comenzar con Linux , eh echo de todo un poco de todos los temas en dev++ pero ya quiero variar , ok espero tu respuesta y seguir en contacto si gustas seria bueno obtener tu ms para intercambiar informacion bueno me despido espero que puedan apreciar mi proyecto :



ATTE : ANTON RAMIREZ , LEONARDO VLADIMIR  (ALUMNO UNI)


Código
  1. #include <windows.h>//para los message box
  2. #include <iostream>
  3. #include <stdio.h> // Operaciones de archivos
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <conio.h>
  7. #include <ctype.h> // Operaciones toupper/tolower
  8. using namespace std;
  9.  
  10. struct CLIENTE
  11. {
  12. char Cod[5];
  13. char Nombre[25];
  14. char Direccion[28];
  15. char Tipo;
  16. char tel[10];
  17.  
  18. };
  19. // Declaracion global de la variable "Registro" de tipo struct CLIENTE
  20. struct CLIENTE Registro;
  21.  
  22. // Declaracion global de la variable "*F" (apuntador de tipo archivo)
  23. FILE *F;
  24.  
  25. int MenuCLIENTE();
  26. void IngresarRegCLIENTE(); // Denominado tambien rutina de Altas
  27. void BuscarxCodCLIENTE(); // Denominado tambien rutina de Consultas
  28. void ActualizacionxCodCLIENTE(); // Denominado tambien rutina de Modificaciones
  29. void EliminacionLogicaxCodCLIENTE(); // Denominado tambien rutina de Baja Logica
  30. void EliminacionFisicaxCodCLIENTE(); // Denominado tambien rutina de Baja Fisica
  31. void MostrarRegCLIENTE();
  32. void Encabezado1();
  33. void Raya58();
  34. void Raya60();
  35. int Menu();
  36. void ordenarxcod();
  37. void ordenarxnom();
  38. void cuadro(int i,int j,int k,int l);
  39. int main()
  40. {
  41. int Opcion;
  42. do
  43. {
  44. Opcion = MenuCLIENTE();
  45. switch(Opcion)
  46. {
  47. case 1 : IngresarRegCLIENTE();
  48. break;
  49. case 2 : BuscarxCodCLIENTE();
  50. break;
  51. case 3 : ActualizacionxCodCLIENTE();
  52. break;
  53. case 4 : EliminacionLogicaxCodCLIENTE();
  54. break;
  55. case 5 : EliminacionFisicaxCodCLIENTE();
  56. break;
  57. case 6 : MostrarRegCLIENTE();
  58. break;
  59. case 7 : ordenarxcod();
  60. break;
  61. case 8 : ordenarxnom();
  62. break;
  63. }
  64. }while(Opcion != 0);
  65. system("pause");
  66. MessageBox(NULL, "Adios Gracias Por Usar Este Programa", "Adios =(", MB_ICONINFORMATION | MB_OK | MB_SYSTEMMODAL);
  67. return(0);
  68. }
  69.  
  70. int MenuCLIENTE()
  71. {
  72. int i;
  73. textbackground(BLUE);
  74. do
  75. {
  76. system("cls");
  77. cuadro(1,1,80,25);
  78. cuadro(28,2,50,4);
  79. textcolor(LIGHTGREEN);
  80. /*cout << "\n\n\r A R C H I V O D E C L I E N T E S";
  81.  cout << "\n\n\r Archivos SECUENCIALES en Lenguaje C ";
  82.  textcolor(WHITE);
  83.  cout << "\n\n\n\r 1.- INGRESAR Registros";
  84.  cout << "\n\r 2.- BUSCAR por CODIGO";
  85.  cout << "\n\r 3.- ACTUALIZAR Datos por CODIGO";
  86.  cout << "\n\r 4.- Eliminacion LOGICA por CODIGO";
  87.  cout << "\n\r 5.- Eliminacion FISICA por CODIGO (defragmentar)";
  88.  cout << "\n\r 6.- MOSTRAR Registros";
  89.  cout << "\n\r 7.- ORDENAR Registro por CODIGO";
  90.  cout << "\n\r 8.- ORDENAR Registro por NOMBRE";
  91.  textcolor(LIGHTRED);
  92.  cout << "\n\r 0.- TERMINAR";*/
  93. textcolor(WHITE);
  94. gotoxy(30,3);
  95. textcolor(LIGHTRED);
  96. printf("ARCHIVO DE CLIENTES");
  97. gotoxy(15,5);printf("0.- TERMINAR");
  98. textcolor(LIGHTGREEN);
  99. gotoxy(15,7);printf("1.- INGRESAR Registros");
  100. gotoxy(15,9);printf("2.- BUSCAR Regsitros por CODIGO");
  101. gotoxy(15,11);printf("3.- ACTUALIZAR Datos por CODIGO");
  102. gotoxy(15,13);printf("4.- ELIMINACION LOGICA por CODIGO");
  103. gotoxy(15,15);printf("5.- ELIMINACION FISICA (Defragmentar)");
  104. gotoxy(15,17);printf("6.- MOSTRAR Registros");
  105. gotoxy(15,19);printf("7.- ORDENAR Registros por CODIGO");
  106. gotoxy(15,21);printf("8.- ORDENAR Registros por NOMBRE");
  107. textcolor(LIGHTRED);
  108. gotoxy(15,23);printf(" Escojer su Opcion---------------------> ");
  109. textcolor(WHITE);
  110. cin >> i;
  111. }while(i<0 || i>8);
  112. return(i);
  113.  
  114. }
  115.  
  116. void IngresarRegCLIENTE()
  117. {
  118. char Codigo[15];
  119. system("cls");
  120.  
  121. cout << "\n\r INGRESAR REGISTROS DE CLIENTES";
  122. // Intenta abrir el archivo CLIENTES.SEC en modo de lectura/escritura
  123. F = fopen("Cliente.Sec","rb+");
  124. if(F == NULL)
  125. {
  126. // Crea el archivo en caso de no existir
  127. F = fopen("Cliente.Sec","wb");
  128. }
  129.  
  130. cout << "\n\n\n\rCodigo ---------> ";getchar();
  131. //gets(Codigo);
  132. cin>>Codigo;
  133. fread(&Registro,sizeof(Registro),1,F); // Lee el Registro, de tamano=sizeof(Registro) del archivo "F"
  134. // Ciclo mientras no se encuentre el final del archivo
  135. while(!feof(F))
  136. {
  137. if(strcmp(Registro.Cod, Codigo)== 0)
  138. {
  139. cout << "\n\n\n\rRegistro DUPLICADO ...!!!";
  140. fclose(F);
  141. getch();
  142. return;
  143. }
  144. fread(&Registro,sizeof(Registro),1,F);
  145. }
  146.  
  147. strcpy(Registro.Cod, Codigo);
  148. cout << "\n\rNombre ----------> ";getchar();
  149. gets(Registro.Nombre);
  150. cout << "\n\rDireccion ---------> ";
  151. gets(Registro.Direccion);
  152. cout << "\n\rTelefono/celular ---> ";
  153. gets(Registro.tel);
  154. cout << "\n\rTipo--> ";
  155. cin >> Registro.Tipo;
  156.  
  157. // Grabar el Registro completo
  158. fwrite(&Registro, sizeof(Registro), 1, F);
  159. fclose(F); // Cierra el archivo
  160.  
  161. cout << "\n\n\n\rCLIENTE registrado !!!\n";
  162. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  163. getch();
  164. return;
  165. }
  166.  
  167. void BuscarxCodCLIENTE()
  168. {
  169. //Numero de producto que desea consultar
  170. char Codigo[15];
  171. system("cls");
  172.  
  173. cout << "\n\rBUSCAR REGISTROS POR CODIGO DE CLIENTES";
  174. // Intenta abrir el archivo CLIENTES.SEC, en modo de solo lectura
  175. F = fopen("Cliente.Sec","rb");
  176.  
  177. if(F == NULL)
  178. {
  179. cout << "\n\n\n\rNo existe el archivo !!!\n";
  180. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  181. getch();
  182. return;
  183. }
  184.  
  185. cout << "\n\n\n\r Codigo ---------> "; getchar(); gets(Codigo);
  186.  
  187. // Lee el "Registro", de tamano=sizeof(Registro) del archivo "F"
  188. fread(&Registro, sizeof(Registro), 1, F);
  189.  
  190. while(!feof(F))
  191. {
  192. if(strcmp(Registro.Cod, Codigo)==0)
  193. {
  194. Encabezado1();
  195. printf("\n%-8s%-25s%-25s%12s %-5c",Registro.Cod,Registro.Nombre,Registro.Direccion, Registro.tel,Registro.Tipo);
  196. Raya60();
  197. getch();
  198. return;
  199. }
  200. fread(&Registro, sizeof(Registro), 1, F);
  201. }
  202. cout << "\n\rNo se encuentra ese registro !!!\n";
  203. fclose(F);
  204. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  205. getch();
  206. return;
  207. }
  208.  
  209. void ActualizacionxCodCLIENTE()
  210. {
  211. // Codigo de CLIENTE que desea modificar
  212. char Codigo[15];
  213. int op;
  214. system("cls");
  215.  
  216. cout << "\n\rACTUALIZAR REGISTROS POR CODIGO DE CLIENTES";
  217. // Intenta abrir el archivo CLIENTES.dat en modo de lectura/escritura
  218. F = fopen("Cliente.Sec","rb+");
  219. if(F == NULL) // Valida la existencia del archivo
  220. {
  221. cout << "\n\n\n\rNo existe el archivo !!!\n";
  222. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  223. getch();
  224. return;
  225. }
  226.  
  227. cout << "\n\n\n\rCodigo ---------> "; getchar(); gets(Codigo);
  228. // Lee el "Registro", de tamano=sizeof(Registro) del archivo "F"
  229. fread(&Registro, sizeof(Registro), 1, F);
  230.  
  231. while(!feof(F))
  232. {
  233. if(strcmp(Registro.Cod, Codigo)==0)
  234. {
  235. Encabezado1();
  236. printf("\n%-8s%-25s%-25s%12s %-5c",Registro.Cod,Registro.Nombre,Registro.Direccion, Registro.tel,Registro.Tipo);
  237. Raya60();
  238. cout << "\n\n\n\r";
  239. system("pause");
  240. do
  241. {
  242. op = Menu();
  243. switch(op)
  244. {
  245. case 1 : system("cls");
  246. textcolor(LIGHTGREEN);
  247. cout << "\n\n\r Actualizacion de Clientes";
  248. textcolor(WHITE);
  249. cout << "\n\n\n\rIngrese nuevo dato";
  250. cout << "\n\rNombre ---------> "; getchar(); gets(Registro.Nombre);
  251. system("cls");
  252. break;
  253. case 2 : system("cls");
  254. textcolor(LIGHTGREEN);
  255. cout << "\n\n\r Actualizacion de Clientes";
  256. textcolor(WHITE);
  257. cout << "\n\n\n\rIngrese nuevo dato";
  258. cout << "\n\rDireccion --------> ";getchar(); gets(Registro.Direccion);
  259. system("cls");
  260. break;
  261. case 3 : system("cls");
  262. textcolor(LIGHTGREEN);
  263. cout << "\n\n\r Actualizacion de Clientes";
  264. textcolor(WHITE);
  265. cout << "\n\n\n\rIngrese nuevo dato";
  266. cout << "\n\rTipo--> "; cin >> Registro.Tipo;
  267. system("cls");
  268. break;
  269.  
  270. }
  271. }while(op != 0);
  272.  
  273. /**Es necesario reposicionar el apuntador del archivo al principio del
  274.  * registro que desea modificar, ya que al leer un registro, el
  275.  * apuntador se posiciona en el registro siguiente
  276.  * La funcion ftell(F) devuelve la posicion donde se encuentra el
  277.  * apuntador
  278.  */
  279. fseek(F, ftell(F)-sizeof(Registro), SEEK_SET);
  280. // Graba el registro con los nuevos campos
  281. fwrite(&Registro, sizeof(Registro), 1, F);
  282. fclose(F);
  283. cout << "\n\n\n\rRegistro modificado !!!\n";
  284. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  285. getch();
  286. return;
  287. }
  288. fread(&Registro, sizeof(Registro), 1, F);
  289. }
  290. cout << "\n\rNo se encuentra ese registro !!!\n";
  291. fclose(F);
  292. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  293. getch();
  294. return;
  295. }
  296.  
  297. void EliminacionLogicaxCodCLIENTE()
  298. {
  299. //numero de codigo que desea eliminar
  300. char Codigo[15], op;
  301. system("cls");
  302.  
  303. cout << "\n\rELIMINACION LOGICA DE REGISTROS DE CLIENTES";
  304. F = fopen("Cliente.Sec","rb+");
  305. if(F == NULL) // Checa la existencia del archivo
  306. {
  307. cout << "\n\n\n\rNo existe el archivo !!!\n";
  308. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  309. getch();
  310. return;
  311. }
  312.  
  313. cout << "\n\n\n\rCodigo --------> "; getchar(); gets(Codigo);
  314.  
  315. fread(&Registro, sizeof(Registro), 1, F);
  316. while(!feof(F))
  317. {
  318. if(strcmp(Registro.Cod, Codigo)==0)
  319. {
  320. Encabezado1();
  321. printf("\n%-8s%-25s%-25s%12s %-5c",Registro.Cod,Registro.Nombre,Registro.Direccion, Registro.tel,Registro.Tipo);
  322. Raya60();
  323.  
  324. strcpy(Registro.Cod, "----");
  325. strcpy(Registro.Nombre, "----");
  326. strcpy(Registro.Direccion, "----");
  327. Registro.Tipo = '0';
  328. do {
  329. cout << "\n\n\r¿... SEGURO que desea BORRARLO ...? [S/N] ---> ";
  330. cin>>op;
  331. op=toupper(op);
  332. }while(op!='S' && op!='N');
  333.  
  334. if(op == 'S')
  335. {
  336. /** Es necesario reposicionar el apuntador del archivo al principio del
  337.  * registro que desea modificar, ya que al leer un registro, el
  338.  * apuntador se posiciona en el registro siguiente
  339.  * La funcion ftell(F) devuelve la posicion donde se encuentra el
  340.  * apuntador
  341.  */
  342. fseek(F, ftell(F)-sizeof(Registro), SEEK_SET);
  343. fwrite(&Registro, sizeof(Registro), 1, F);
  344. cout << "\n\n\n\rRegistro eliminado !!!\n";
  345. }
  346. fclose(F);
  347. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  348. getch();
  349. return;
  350. }
  351. fread(&Registro, sizeof(Registro), 1, F);
  352. }
  353. cout << "\n\rNo se encuentra ese registro !!!\n";
  354. fclose(F); // Cierra el archivo
  355. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  356. getch();
  357. return;
  358. }
  359.  
  360. void EliminacionFisicaxCodCLIENTE()
  361. {
  362. //Variable para controlar el archivo temporal
  363. FILE *Temporal;
  364. system("cls");
  365.  
  366. cout << "\n\rELIMINACION FISICA DE REGISTROS DE CLIENTES";
  367. // Intenta abrir el archivo CLIENTES.SEC en modo de solo lectura
  368. F = fopen("Cliente.Sec","rb");
  369. // Valida la existencia del archivo
  370. if(F == NULL)
  371. {
  372. cout << "\n\n\n\rNo existe el archivo !!!\n";
  373. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  374. getch();
  375. return;
  376. }
  377. // Crea el archivo Temporal.Sec
  378. Temporal = fopen("Temporal.Sec","wb");
  379.  
  380. fread(&Registro, sizeof(Registro), 1, F);
  381. while(!feof(F))
  382. {
  383. if(strcmp(Registro.Cod, "----")!= 0)
  384. // Graba el registro valido en el archivo temporal
  385. fwrite(&Registro, sizeof(Registro), 1, Temporal);
  386. //Lee el siguinete elemento del archivo
  387. fread(&Registro, sizeof(Registro), 1, F);
  388. }
  389. //fcloseall(); // Cierra todos los archivos abiertos
  390. fclose(F);
  391. fclose(Temporal);
  392. remove("Clientes.Sec"); //Elimina el archivo original
  393. rename("Temporal.Sec", "Clientes.Sec");
  394. //Renombra el archivo temporal con el nombre del archivo original
  395.  
  396. cout << "\n\n\n\rArchivo DEFRAGMENTADO ... !!!\n";
  397. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  398. getch();
  399. return;
  400. }
  401.  
  402. void MostrarRegCLIENTE()
  403. {
  404. system("cls");
  405.  
  406. cout << "\n\r\t\t\tLISTADO DE REGISTROS DE CLIENTES\n\n";
  407. F = fopen("Cliente.Sec","rb");
  408. if(F == NULL)
  409. {
  410. cout << "\n\n\n\rNo existe el archivo !!!\n";
  411. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  412. getch();
  413. return;
  414. }
  415.  
  416. Encabezado1();
  417. fread(&Registro, sizeof(Registro), 1, F);
  418. while(!feof(F))
  419. {
  420. printf("\n%-8s%-25s%-25s%12s %-5c",Registro.Cod,Registro.Nombre,Registro.Direccion, Registro.tel,Registro.Tipo);
  421. fread(&Registro,sizeof(Registro),1,F);
  422. }
  423. fclose(F); // Cierra el archivo
  424. Raya60();
  425. cout << "\n\rFin del listado !!!\n";
  426. cout << "\n\r<<< ... PRESIONE ENTER para continuar >>>";
  427. getch();
  428. return;
  429. }
  430.  
  431. void Encabezado1()
  432. {
  433. Raya58();
  434. cout << "\nCODIGO N O M B R E D I R E C C I O N TELEFONO TIPO";
  435. Raya60();
  436. }
  437.  
  438. void Raya58()
  439. {
  440. cout << "\n\r==============================================================================";
  441. }
  442.  
  443. void Raya60()
  444. {
  445. cout << "\n\r------------------------------------------------------------------------------";
  446. }
  447.  
  448. int Menu()
  449. {
  450. int i;
  451. do
  452. {
  453. system("cls");
  454. textcolor(LIGHTGREEN);
  455. cout << "\n\n\r Actualizacion de Clientes";
  456. textcolor(WHITE);
  457. cout << "\n\n\n\r 1.- ACTUALIZAR Nombre";
  458. cout << "\n\r 2.- ACTUALIZAR Direccion";
  459. cout << "\n\r 3.- ACTUALIZAR Tipo";
  460. textcolor(LIGHTRED);
  461. cout << "\n\r 0.- TERMINAR";
  462. textcolor(WHITE);
  463.  
  464. cout << "\n\n\n\r Seleccione su opcion ---> ";
  465. cin >> i;
  466. }while(i<0 || i>3);
  467. return(i);
  468. }
  469. void ordenarxcod(){
  470. FILE *F;
  471. CLIENTE A,B,aux;
  472. int i,j,n;
  473. F=fopen("Cliente.Sec","rb+");
  474. if(F==NULL){
  475. printf("No se puede abrir el archivo.\n");
  476. exit(1);
  477. }
  478. fseek(F,0,SEEK_END);
  479. n=ftell(F)/sizeof(A);
  480. for(i=0;i<=n-1;i++){
  481. for(j=i+1;j<=n;j++){
  482. fseek(F,i*sizeof(A),SEEK_SET);
  483. fread(&A,sizeof(A),1,F);
  484. fseek(F,j*sizeof(B),SEEK_SET);
  485. fread(&B,sizeof(B),1,F);
  486. if(strcmp(A.Cod,B.Cod)==1){
  487. aux=A;
  488. A=B;
  489. B=aux;
  490. fseek(F,i*sizeof(A),SEEK_SET);
  491. fwrite(&A,sizeof(A),1,F);
  492. fseek(F,j*sizeof(B),SEEK_SET);
  493. fwrite(&B,sizeof(B),1,F);
  494. }
  495. }
  496. }
  497. MostrarRegCLIENTE();
  498. }
  499. void ordenarxnom(){
  500. FILE *F;
  501. CLIENTE A,B,aux;
  502. int i,j,n;
  503. F=fopen("Cliente.Sec","rb+");
  504. if(F==NULL){
  505. printf("No se puede abrir el archivo.\n");
  506. exit(1);
  507. }
  508. fseek(F,0,SEEK_END);
  509. n=ftell(F)/sizeof(A);
  510. for(i=0;i<=n-1;i++){
  511. for(j=i+1;j<=n;j++){
  512. fseek(F,i*sizeof(A),SEEK_SET);
  513. fread(&A,sizeof(A),1,F);
  514. fseek(F,j*sizeof(B),SEEK_SET);
  515. fread(&B,sizeof(B),1,F);
  516. if(strcmp(A.Nombre,B.Nombre)==1){
  517. aux=A;
  518. A=B;
  519. B=aux;
  520. fseek(F,i*sizeof(A),SEEK_SET);
  521. fwrite(&A,sizeof(A),1,F);
  522. fseek(F,j*sizeof(B),SEEK_SET);
  523. fwrite(&B,sizeof(B),1,F);
  524. }
  525. }
  526. }
  527. MostrarRegCLIENTE();
  528. }
  529. void cuadro(int i,int j,int k,int l){
  530. register int a;
  531. for(a=j+1;a<l;a++){
  532. gotoxy(i,a);
  533. printf("%c",186);
  534. gotoxy(k,a);
  535. printf("%c",186);
  536. }
  537. for(a=i+1;a<k;a++){
  538. gotoxy(a,j);
  539. printf("%c",205);
  540. gotoxy(a,l);
  541. printf("%c",205);
  542. }
  543. gotoxy(i,j);printf("%c",201);
  544. gotoxy(k,j);printf("%c",187);
  545. gotoxy(i,l);printf("%c",200);
  546. gotoxy(k,l);printf("%c",188);
  547. gotoxy(1,1);
  548. }


Título: Re: OPERACIONES BASICAS CON FILES
Publicado por: Garfield07 en 13 Diciembre 2010, 19:55 pm
Bueno, primero de nada, aunque creo que es de verdad por nada...
Luego, ese codigo para mi esta mucho mejor...

y aparte. El codigo C en linux es muy sencillo. Simplemente creo que de lo que sabes, quita las APIs que olvides, algunas librerias ya no existen en esta orilla, y los sockets son mucho mas faciles.
Usas Ubuntu? Recomiendo 9.04.
Sencillo. Lo mejor de Linux es su complicada sencillez.
Olvida Dev-Cpp. Es el peor compilador (opinion personal) del mundo. Si sigues programando en windows, Code-Brocks.
Luego, si no en linux hay un programa llamado "gedit". Aplicaciones>1º menu>Editor de textos gedit. Escribes y guardas como "code.c". Terminal (Aplicaciones>1º menu>Terminal. ), vas a la carpeta "cd Es*", y compilas (gcc -o code code.c).
Para probarlo, terminal, "./code" [el punto es la carpeta en la que estas. Es un metodo rapido de linux]

Creo que es excesivamente explicado...
Pregunta lo que quieras.
De nada otra vez (nada da mas alegria que alguien agradecido xD)