elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


  Mostrar Mensajes
Páginas: 1 [2] 3 4
11  Programación / Programación C/C++ / Re: La serie mas larga? en: 15 Febrero 2011, 21:18 pm
Si no sabemos qué es lo que hacen tus otras funciones, decir que ayudemos sería como ofuscar el código... es posible, pero lo mejor sería que nos facilites el trabajo si es que te vamos a ayudar...

Por lo menos pon una descripcion de que hace cada función. Por ejemplo, yo al principio supuse que leer_e ingresaba los numeros en tl, pero también la usas más abajo, además no entiendo para que es el argumento x, ni por que el primer entero lo introduces en un scanf en el main y no lo haces todo de una en leer_e... Y obviamente que deduzco quecuando le pasas nl como argumento, en la función está definido por referencia, de modo que la función pueda inicializarla...

Osea, puede ser un error en el ingreso, es muy importante que facilites las funciones, después de todo, ¿cuanto tiempo te puede llevar copiar y pegarlas?
Directamente pon todo el código, incluyendo las definiciones que hagas al principio...
12  Programación / Programación C/C++ / Re: ayuda con practica en: 24 Enero 2011, 02:54 am
Te creo que no te lo dio nadie, porque he leído otro post tuyo donde decía que estabas aprendiendo de no sé cual manual...


Lo recomendable sería que uses iteraciones (bucles), si sólo quieres saber el mayor y el menor...
Osea, imaginate que tu eres la computadora y tienes que determinar cuál es el mayor de n números... ¿Qué hacés tú en tú cabeza para hacer esto? Podrías explicarlo, y no hacerlo de forma intuitiva? Y, lo más obvio que se te ocurrirá será que compararás el primero con el segundo, te memorizarás el mayor y lo compararaás con el tercero, memorizarás el mayor de ésta nueva comparación y pasarás al cuarto y harás esto con todos los números...

En el caso que todavía no hayas llegado a las iteraciones (el uso de instrucciones for, while...) y lo tengas que hacer con if  te recomiendo que si sabes usar else, lo uses, el programa será más óptimo...
Sino, también se puede hacer sin else, pero hará más preguntas de las necesarias ¿entiendes? Es que cuando tu preguntas algo, tanto la respuesta afirmativa como la negativa te dan informacion y tienes que aprovechar ambas... de no usar el else estarías haciendo una mala práctica, a mi criterio...

Bueno, imagina que son 3 números (a, b y c) en vez de 5 y yo hago:

¿a es mayor que b y éste último a su vez mayor que c?
SI--> camino 1
NO-->camino 2

Camino 1: (en esta situación tendríamos en orden descendente "a,b,c") Entonces el mayor es a...


Camino 2: (en esta situación tendríamos en orden descendente "b,a,c" o "b,c,a" o "c,b,a" o "c,a,b" ) Entonces, nos bastará preguntar: ¿b es mayor que c?
SI-->camino 2-1
NO-->camino 2-2

Camino 2-1: el mayor es b
Camino 2-2 el mayor es c



Bueno, espero que veas así claramente que la respusta dicotómica (si o no) ofrece información que no debe ser desperdiciada...

Obviamente que pordías preguntar a es mayor que b, y a es mayor que c? SI--> a es el mayor de los tres
Punto y aparte
b es mayor que a, y b es mayor que c? SI--> b es el mayor de los tres
Punto y aparte
c es mayor que b, y c es mayor que a? SI--> c es el mayor de los tres
Punto y aparte

Pero sería, repito, un desperdicio de preguntas
13  Programación / Programación C/C++ / Re: Patrón de bucle en: 20 Enero 2011, 06:36 am
No hay porque pelearse, es una comunidad de cooperación.
Yo vuelvo a pedir disculpas por sí lo dije de una manera muy fuerte o si pareción una generalización...  :D
14  Programación / Programación C/C++ / Re: Patrón de bucle en: 20 Enero 2011, 03:25 am
Pues bien, me agrada haberte podido ayudarte, sin embargo, querría que me mandes un MP porque me quedé con la duda sobre como era en verdad el enunciado...  :huh:
Como bien, yo detecté la repetición, más bien no sé a que consigna responde, puesto que no he comprendido lo que decías.

Y pues creo que que esto está completamente de sobra:
Citar
Te garantizo que puedo expresarme mucho mejor que tú (almenos de forma escrita)
¿O acaso tan bien me conoces? Además, en todas mis respuestas en el foro, siempre me he escrito de forma más o menos coherente de forma automática (estando apurado o no)
Aparte, he colaborado (y seguiré haciéndolo) de manera asidua...
No suelo ser ni fanático de la gramática (y mucho menos de la ortografía) siempre que no ocasione problemas en la comprensión...
Yo tampoco quise tildarte de lelo o algo por el estilo, resalté la falta de cohesión en el caso particular de la duda que planteaste, nunca generalizaría...
15  Programación / Programación C/C++ / Re: Patrón de bucle en: 19 Enero 2011, 20:50 pm
Te explicas muy mal... tal vez te ayuden si supieses escribir tus ideas con mas coherencia...
pero supongo, por lógica intuitiva que lo que le sigue a tu patrón es:
903696309
903690096309
y así...
Muy intuitivamente, ya que el enunciado no se comprende para nada...
16  Programación / Programación C/C++ / Re: Base de datos en C++ en: 19 Enero 2011, 18:48 pm
Tengo varias aclaraciones:



-Utiliza las etiquetas GeSHi para que el código se vea más claro (más para los otros que para mí, yo copio y pego el código siempre en mi editor xD)



-En todas las funciones tipo void no pones el return, ya sé que no es problema ponerlo al final, pero una vez me dijieron que era de buena educación xD



-Declaras el dato media, tipo double (donde supongo que pondrías el promedio de las notas) y no lo utilizas... (no lo calculas, no lo muestras)



-Inicilizas la variable last_al en 1 y usas esta variable para indicar la posicion del vector de estructuras a modificar. No estás utilizando la posición 0, la desperdicias...



-En el bucle principal (el while del main) estás comparando una variable no inicializada. Osea... ¿Qué pasaría si cuando declaras choice, esta por casualidad empieza con 0 adentro de sí?... te lo dejo a tu lógica pensar en las consecuencias... Yo utilizaría un do {}while así comparas luego del ingreso



-En la funcion opciones () en caso de que la variable ingresada opcion no sea 0, no esta puesto que valor retornará. Osea:
Código
  1. if (opcion == 0){
  2. return opcion;
  3. }
  4.  
Realmente esto es totalmente inecesario, porque no directamente devuelves opcion. Osea, te fijas que opcion sea 0 para devolver opcion... Y ensima tienes el error de que cuando no es 0 no esta definido el retorno

Yo sinceramente haría una funcion que reuna a menu() y opciones(), que me desplegue el menu y me haga elegir la opcion, retorne el valor elegido y el switch lo pongo en el main... no sé, fijate vos...



-Ya que estás contando en last_al el número de alumnos agregados, por qué no hacer que no permita mas ingresos que MAX_AL?



-Restringe tus ingresos, no quieres que te introduzcan notas mayores al rango con el que estás trabajando. Del mismo modo que deberías aclararle a alguien que introduce una opción incorrecta en el menú, que la opción es inválida. Y especialmente no quieres que elegir_al() te permita elegir alumnos mas alla de MAX_AL-1... de lo contrario podrías tener errores fatales...



-No sé por qué si tu función elegir_al() tiene un clear() al principio, muchas veces que la llamas desde otras funciones haces un clear() exactamente antes de llamarla...
Además en la función mod() olvidas un clear(); entre elegir_al() y lo que sigue en la función... (en show() si lo pones)


-En la función show declaras esperar sólo para "pausar" la ejecución... podrías utilizar elec_al porque ya no lo necesitarás... Además, sería mejor que lo declarases al inicio de la función...


-Cuando tu dices "Borrar los datos de un alumno"? no sería mejor que si lleno mi base con 20 alumnos (llengando al maximo impuesto) y borro los datos del alumno 1, los datos del alumno i pasen a donde los del alumno i-1 a partir de i=2? Así, borrando uno podría volver a ingresar otro alumno a pesar de haber llegado a la máxima cantidad... podés planteartelo como un desafío personal...
Sino, tendríamos que borrar el dato de un alumno x, y para ingresar otro, tendríamos que modificar a x... Pero entonces el paso de borrar sería innecesario, porque directamente modificando ser sobreescriben los valores anteriores...



-Sigue programando y divirtiendote  ;-) me gusto tu forma de limpiar la pantalla, sin usar una llamada al sistema ni cosas de librerias no estandar... además me gusta el número 22...
17  Programación / Programación C/C++ / Re: ¿Errores en los enunciados de un examen de C? en: 19 Enero 2011, 17:56 pm
-Bueno, pués supuse que era algo así. Yo voy a la secundaria y tuve una profesora que a la hora de hacer un exámen le pedía alguno de los años anteriores a otros profesores y ni se fijaba si se había correjido algo...
Era ing en sistemas y no tenía más p*** idea de como programar... Ni siquiera las cosas más simples xD...
Profesores como esos hay por todas partes, lo peor que te puede pasar es que ensima sean unos tercos y no acepten una acotación del alumno... Pero en programación no hay mucha vuelta basta apretar F9 para darse cuenta quién tenía razón...



-Con respecto a la estructura cola, la parte positiva de tener declarado el tipo de dato nodcola es la posibilidad de retornar ese tipo (aunque no declares más de una variable de ese tipo)
Un ejemplo de ésto:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. struct punto {
  5.       int x, y;
  6.       };
  7.  
  8. struct punto funcion (void) {
  9.     struct punto p;
  10.     p.x=0;
  11.     p.y=0;
  12.     return p;
  13.     }
  14.  
  15. int main(int argc, char *argv[])
  16. {
  17.  struct punto a;
  18.  a.x=6;
  19.  a.y=6;
  20.  printf ("%i %i\n", a.x, a.y);
  21.  a = funcion ();
  22.  printf ("%i %i\n", a.x, a.y);
  23.  system("PAUSE");
  24.  return 0;
  25. }
  26.  



Citar
Aunque la estructura que contiene los punteros principio y final esté declarada fuera del main, siguen siendo locales a la estructura en los que fueron declarados y por eso los paso por referencia, ¿no?

Debo reconocer que lo que aquí planteas me ha hecho dudar de mis convicciones. Pero he probado y te paso un ejemplo para que compiles y te des cuenta por tigo mismo que pueden existir estructuras globales (siempres que la variable sea declarada fuera de toda función)...

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. struct punto {
  5.       int x, y;
  6.       };
  7. struct punto p;
  8.  
  9. void funcion (void) {
  10.     p.x=0;
  11.     p.y=0;
  12.     return;
  13.     }
  14.  
  15. int main(int argc, char *argv[])
  16. {
  17.  p.x=6;
  18.  p.y=6;
  19.  printf ("%i %i\n", p.x, p.y);
  20.  funcion ();
  21.  printf ("%i %i\n", p.x, p.y);
  22.  system("PAUSE");
  23.  return 0;
  24. }
  25.  

Osea una cosa es la definición de la estructura
Código
  1. struct punto {
  2.       int x, y;
  3.       };
Y otra distinta la declaración de la variable del tipo de esa estructura:
Código
  1. struct punto p;

Si la definición de la estructura (de la plantilla como dices tu) está fuera de cualquier función (main es una), significa que en todo el código podrás declarar variables de ese tipo...
Si la declaración de la variable está fuera de toda función, esa variable será visible para todas las funciones...



-Con lo que te puse sobre las referencias, ahora me doy cuenta que sólo se puede hacer en c++, es para ahorrarse tantos (*) y evitar errores de distracción que pueden ser difiíciles de detectar. Un ejemplo

Es lo mismo hacer esto:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void funcion (int *x) {
  5.     *x=0;
  6.     return;
  7.     }
  8.  
  9. int main(int argc, char *argv[])
  10. {
  11.  int a;
  12.  a=6;
  13.  printf ("%i\n", a);
  14.  funcion (&a);
  15.  printf ("%i\n", a);
  16.  system("PAUSE");
  17.  return 0;
  18. }
  19.  

Que esto:

Código
  1. #include <cstdlib>
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6. void funcion (int &x) {
  7.     x=0;
  8.     return;
  9.     }
  10.  
  11. int main(int argc, char *argv[])
  12. {
  13.    int a;
  14.    a=6;
  15.    printf ("%i\n", a);
  16.    funcion (a);
  17.    printf ("%i\n", a);
  18.    system("PAUSE");
  19.    return 0;
  20. }
  21.  

Pero lo último, como ves, lo tuve que hacer en C++ porque en C no existe...



-En cuanto a la función malloc, este sí que es un problema importante, y puede traerte comportamientos no deseados del programa (por ejemplo cuando sale el cartelito que dice que el programa "no responde"), y luego tu puedes pensar que el problema deriva de no estar pasando por referencia las variables ya que así te funciona "de casualidad":

La memoria utilizada hay q reservarla (por eso declaras las variables, para que tu programar sepa cuánta memoria reservar) Pero...  ¿que sucede en casos como éste que necesito ir declarando nuevos nodos a medida que los voy necesitando?

Bueno en este caso se recuerre a funciones como éstas que reservan un pedacito de memoria de determinado tamaño. La función malloc cuando es llamada, reserva una memoria del tamaño que se le pase por argumento. Ahora... ¿como manejamos la memoria que ha reservado dicha función?. Pues porque la función devuelve la dirección de memoria del espacio que te reservo...
Así si yo quiero declarar un nuevo nodo tengo que tener en claro:
-cuanta memoria reservar, osea, cuanta memoria ocupa el nodo.
-un puntero hacia un tipo nodo, para poder guardar la dirección de la memoria reservada.
Para el primer apartado, tengo que saber el peso de un nodo. De que tipo es el nodo? (Struct Componente). Y por ende uso la función sizeof para saber cuanto pesa...
Para lo segundo apartado, declaro un puntero del tipo (struct componente*) para almacenar la dirección de memoria devuelta (lo habíamos definido como Puntero a este tipo)

Código
  1. Puntero a;
  2. a = (Puntero) malloc (sizeof(struct Componente);
  3.  
*el "(Puntero)" es porque malloc devuelve un puntero void (void*) y tienes que hacer la conversión...


-Bueno, espero que te quede claro que un código vale más que mil explicaciones... por ende cuando no entiendas algo, has tu propio "experimento" como los ejemplos que te puse
18  Programación / Programación C/C++ / Re: ¿Errores en los enunciados de un examen de C? en: 19 Enero 2011, 02:37 am
Pués bien, mis hipótesis se confirman... La estructura Cola (en tu código la llamas nodcola), que contiene dos punteros hacia estructuras Componentes, es para manejar la lista, teniendo siempre una referencia al principio y al final de la cadena...

Creí eso, pero no quise preguntarte para no liarte tanto. Porque... para qué quieres declarar el tipo de estructura Cola, si sólo necesitas una variable de ese tipo? Bah, yo creo que si vas a declarar una estructura (una plantilla como tu creo que llamas) es para declarar luego más de una sola variable de ese tipo. Pero en éste caso solo necesitas una variable, para poder almacenar el principio y el final de la lista...
Espero que te quede más claro con esto:

Si haces esto:
Código
  1. struct nodcola {Puntero principio, final};
  2.  

Estás definiendo un nuevo tipo (struct nodcola). Cualquier varible que definas de éste tipo, poseerán dos punteros hacia estructuras Componente.
Así luego podemos hacer:

Código
  1. struct nodcola a,b;
  2. struct componente x,y,z;
  3. x.next=&y;
  4. y.next=&z;
  5. z.next=NULL;
  6. a.principio=&x;
  7. a.final=&z;
  8. /* Para qué necesito la variable b (de tipo nodcola)
  9.     si me basta con a, para tener una referencia del
  10.     principio y del final de la lista enlazada...
  11. */
  12.  

En todo caso podés hacer esto:

Código
  1. struct {Puntero principio, final} Cola;
  2.  
Y ahí estás declarando una variable Cola que contiene en sí dos punteros Cola.principio y Cola.final con los cuales podes apuntar al principio y al final de la lista haciendo algo como:

Código
  1. Cola.principio=&x;
  2. Cola.final=&z
  3.  

Osea, no declaras el tipo "struct nodcola" ya que sólo necesitas UNA variable de ese tipo...

Bueno, éstas fueron aclaraciones tontas, que de verdad no hacen al funcionamiento del programa... Ahora sí unas aclaraciones serias sobre lo que dices y sobre tu código...


-
Citar
Haciendo esto, ya me compilaba, pero tenía errores en el código que he solucionado pero no tengo muy clara la idea de como lo he solucionado

La verdad que no sé como solucionas problemas si no tenés idea clara de como lo estás haciendo, a menos que hagas como muchos alumnos míos que ponen las cosas de diferentes maneras hasta que les compile o funcione...
Un consejo: trata de entender cada cosa que hagas... cada línea que escribas, que sepas certeramente lo que en verdad estás haciendo... Si no la tienes muy claras puedes crear un programa de prueba, en donde probar la parte en cuestión sobre la que tienes dudas y ver como funciona...


-Para poder modificar las variables dentro de las funciones las pasas por referencia. En tu caso pasas un puntero a dichas variables... Pero tu siempre trabajas con la variable apuntada por dicho puntero... Aver si me explico...
Si hago:
Código
  1. Puntero *first;
first es un puntero a un puntero a una estructura componente...
pero tu siempre trabajas con (*first) porque lo que te interesa es el puntero a la estructura componente, no el puntero a este puntero...
Puedes hacer más claro el código si utilizas las variables pasadas por referencia del siguiente modo:
Código
  1. int add_nod(Puntero &first,Puntero &ultimo,int dato)
  2.  
Mirate esto: http://www.mailxmail.com/curso-programacion-c/parametros-valor-referencia


-Tratá de no usar variables globales inecesarias, es cierto que es cómodo que los punteros que tienen la referencia del principio y el final de la lista sean globales, pero para códigos más largos puede llegar a causar confusiones...
En verdad creo que sí algún aspecto positivo tiene declarar el tipo strcut nodcola es que puedes hacer que el retorno de una función sea de dicho tipo y así no tener que usar variables globales ni referencias...


-Te explico el funcionamiento de malloc, porque creo que la utilizas mal
Si yo quiero declarar N variables tipo int hago lo siguiente:
Código
  1. int* puntero;
  2. puntero = (int *) malloc (N*sizeof(int));
  3.  

El argumento indica el tamño del espacio reservado... lo que tu haces es como si yo hiciese acá:

Código
  1. int* puntero;
  2. puntero ( (int *) malloc (N*sizeof(int*));
  3.  

Espero que entiendas lo que tienes que modificar, no pretendas que te lo dé servido...


-En la función ext_nod cuando haces:
Código
  1. if(*first == NULL)
  2.      ultimo = NULL;
  3.  

No estás modificando el valor de Cola.final, sino que estás modificando el puntero que apunta a esta variable... tendrías que modifcar (*ultimo)...


-No sé que es lo que se te pide, pero si la función add_nod crea más nodos al final de la lista, sería más lófico que ext_nod extraiga nodos del final de la cola en vez desde el principio no?


-Utiliza las etiquetas GeSHi para que el código sea más claro...


-Dices que:
Citar
El único problema que habría es que mi profesor declaro la plantilla de estructura pero no declaro una variable de esa plantilla de estructura.
Pero en tu código si utilizas dicha estructura... (osea, declaras variables de dicho tipo)... Supongo que en el código donde no la usabas declarabas directamente:

Código
  1. Puntero principio, final;
  2.  


-Tan preocupado estás por el código de un exámen? y te acuerdas del código perfectamente de dicho exámen? Espero que ésto no sea una tarea, pués sería contrario a las reglas del foro... En cualquier caso en mis explicaciones no doy el código resuelto, sino indicaciones de que hacer para enmendar tus errores...




Si tienes cualquier duda más no temas en hacerla y disculpa si te prejuzgo un poco, pero hay muchos vivos que quieren sus tareas hechas...
Y bueno
19  Programación / Programación C/C++ / Re: comunicacion entre aplicaciones borland c++ builder mediante SOCKET en: 18 Enero 2011, 23:37 pm
Pues creo que entonces si son aplicaciones dentro de un mismo ordenador, por que quieres utilizar comunicación TCP/IP?
Por que no utilizas (aclaro, yo no sé nada de ésto, sólo de vista) algo así como memoria compartida... creo que una vez vi una biblioteca diseñada para ésto... no estoy seguro, espero que otro con más conocimientos que yo te pueda resolver la duda
20  Programación / Programación C/C++ / Re: ¿Errores en los enunciados de un examen de C? en: 15 Enero 2011, 19:03 pm
Yo creo que lo que quiso hacer tu profesor es lo siguiente (tengo muy poca experiencia en listas enlazadas, sé la lógica, pero muchos conceptos los ignoro):

Código
  1. struct Componente {
  2. int dato;
  3. struct Componetne  *sig;
  4. };
  5.  

Hasta ahí, lo que entiendo es que declara el elementeo básica de una lista enlazada: una estructura que tiene un dato y un puntero hacia una estructura de éste mismo tipo (hasta ahí el único error está en el ";" que pongo luego de "struct Componetne  *sig" y el que agrego al final)

Luego hace esto:
Código
  1. typedef Componente *Puntero;
  2.  

Lo cual (o por lo menos con lo poco que sé de C) es incorrecto, porque trata de crear un nuevo tipo llamado "*Puntero" que sea igual al tipo "Componente" (el cuál no existe, existe "struct Componente")

El quiso hacer (en mi opinión)

Código
  1. typedef struct Componente* Puntero;
  2.  

De modo que ahí creaba un nuevo tipo llamado Puntero, que consistía en un puntero a una estructura tipo Componente.
Creo que eso es lo que quisiste poner con:
Citar
Ya que en el primer caso declara un puntero a una estructura del tipo Componente

Ahora lo que haces tú es:
Código
  1. typedef struct Componente Puntero;
  2.  
Ahí como bien dices:
Citar
creo un nuevo tipo de variable a una estructura de tipo componente

Y ahora te respondo la pregunta:
Citar
¿Es lo mismo?
Bueno, creo que te la contestaste solito:
Citar
en el primer caso obtengo un puntero a dicha estructura y en el segundo una variable en si que puede ser accesible por un puntero

Lo que, como bien dices, haces con tu código es crear un tipo llamado Puntero que es lo mismo que struct Componente. Osea, con lo tuyo sería lo mismo hacer:

Código
  1. struct Componente a;
  2. //o hacer:
  3. Puntero a;
  4.  

En vez si quieres q "a" sea un puntero a una estructura componente debes hacer (para tu caso):

Código
  1. struct Componente *a;
  2. //o hacer:
  3. Puntero *a;
  4.  

Ya que en tu caso, te vuelvo a repetir struct Componente vendría a ser lo mismo que Puntero...

Aún así, creo que ya que el tipo de variable que estás definiendo se llama "Puntero" sería mejor que sea un puntero, no?

Pués entonces habría que hacer lo que hice yo arriba (y creo que eso quiso hacer tu profesor)

Código
  1. typedef struct Componente* Puntero;
  2.  

Bueno aquí un ejemplo del uso del mismo:
Código
  1. struct Componente a;
  2. Puntero b;
  3. a.dato=7;
  4. b=&a;
  5. b->dato=33
  6.  

De modo que "a" es una estructura Componente y b un puntero a estructura Componente que luego le asignamos la dirección de "a" y modificamos el contenido de ésta variable a través de "b"...

Luego puedes hacer:

Código
  1. struct Cola { Puntero principio, final; };

Ahi declaras otro tipo de estructura (la estructura Cola) que posee dentro de sí un dos punteros a estructuras Componente.
Sé lo que haces pero no se bien para que la utilizas... necesitaría el código, como te dije tengo muy poca experiencia en ésto de las listas enlazadas y no sé que es una cola, pero tengo claro lo que hiciste ahí... Pero supongo que te viene mejor que sea una estructura con dos punteros a estructuras componentes que una estructura con dos estructuras componentes adentro. Ya que de este modo, podés cambiar el principio y el final (haciendo que dichos punteros apunten a otras estructuras)...

Y la verdad que no entiendo tus problemas sin una explicación un poco más detallada y menos confusa... además del código....


Espero aver ayudado y no haber liado más el asunto...
Páginas: 1 [2] 3 4
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines