View Full Version : password generator ... all combinations
luckyr13
04-15-2008, 07:53 AM
Hi, well... i made the code for a password generator for all the possible combinations so we can make a very interesting dictionary with this... actually u can change the parameters and only make certain combinations (like all numbers combination or all capital letters combinations) ... just had to change a few changes...
The program has some messages in spanish because im mexican so if u need help or a translate version (or maybe another version that supports an specific change) post a comment and i will try to do something about it.
Oh... the program is write in C ... and actually is very simple i guess...
Hope u like it! and sorry for my bad grammar... english is not my first language :D
/************************************************** ****************/
/* GeneradorDiccionario */
/* Version: 1.0 */
/* Autor: luckyr13 */
/* Descripción: Programa que imprime todas las combinaciones */
/* posibles para palabras de 1 a 6 caracteres, auxiliar en */
/* pruebas de ataques basados en diccionario. */
/* Para compilar en Linux: gcc com.c -o com */
/* Para correrlo: ./com */
/* Para almacenarlo: ./com > diccionario.txt */
/* Nota: Para numeros de combinaciones muy altas el contador */
/* final truena debido a las restricciones de los int */
/************************************************** ****************/
#include <stdio.h>
//Imprime todas las combinaciones posibles (numeros, letras, simbolos)
//#define MIN 30
//#define MAX 127
//Imprime todas las combinaciones de binarios
//#define MIN 48
//#define MAX 50
//Imprime todas las combinaciones posibles de Mayusculas
//#define MIN 65
//#define MAX 91
//Imprime todas las combinaciones posibles de minusculas
//#define MIN 97
//#define MAX 123
//Imprime todas las combinaciones posibles de numeros
#define MIN 48
#define MAX 58
void title();
void uno();
void dos();
void tres();
void cuatro();
void cinco();
void seis();
int main() {
title();
int numero=0;
printf("Numero de caracteres del password (1-6) : ");
scanf("%d", &numero);
switch(numero) {
case 1:
uno();
break;
case 2:
dos();
break;
case 3:
tres();
break;
case 4:
cuatro();
break;
case 5:
cinco();
break;
case 6:
seis();
break;
default:
printf("Se salio del rango, ajuste el programa a sus necesidades\n");
}
return 0;
}
void uno() {
int limite=2;
int i=0;
int j=0;
int k=0;
int cont=0;
int val=0;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
printf("%c\n", letra[val][i-MIN]);
cont++;
}
printf("Total de combinaciones: %d\n", cont);
}
void dos() {
int limite=2;
int i=0;
int j=0;
int k=0;
int cont=0;
int val=0;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letra[k][j-MIN]=j;
printf("%c%c\n", letra[val][i-MIN], letra[k][j-MIN]);
cont++;
}
}
printf("Total de combinaciones: %d\n", cont);
}
void tres() {
int limite=3;
int i=0;
int j=0;
int h=0;
int cont=0;
int val=0;
int k=val+1;
int k2=k+1;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letra[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letra[k2][h-MIN]=h;
printf("%c%c%c\n", letra[val][i-MIN], letra[k][j-MIN], letra[k2][h-MIN]);
cont++;
}
}
}
printf("Total de combinaciones: %d\n", cont);
}
void cuatro() {
int limite=4;
int i=0;
int j=0;
int h=0;
int l=0;
int cont=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letra[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letra[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letra[k3][l-MIN]=l;
printf("%c%c%c%c\n", letra[val][i-MIN], letra[k][j-MIN], letra[k2][h-MIN], letra[k3][l-MIN]);
cont++;
}
}
}
}
printf("Total de combinaciones: %d\n", cont);
}
void cinco() {
int limite=5;
int i=0;
int j=0;
int h=0;
int l=0;
int m=0;
int cont=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
int k4=k3+1;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letra[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letra[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letra[k3][l-MIN]=l;
for(m=MIN; m<MAX; m++) {
letra[k4][m-MIN]=m;
printf("%c%c%c%c%c\n", letra[val][i-MIN], letra[k][j-MIN], letra[k2][h-MIN], letra[k3][l-MIN], letra[k4][m-MIN]);
cont++;
}
}
}
}
}
printf("Total de combinaciones: %d\n", cont);
}
void seis() {
int limite=6;
int i=0;
int j=0;
int h=0;
int l=0;
int m=0;
int n=0;
int cont=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
int k4=k3+1;
int k5= k4+1;
//int num=0;
char letra[limite][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letra[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letra[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letra[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letra[k3][l-MIN]=l;
for(m=MIN; m<MAX; m++) {
letra[k4][m-MIN]=m;
for(n=MIN; n<MAX; n++) {
letra[k5][n-MIN]=n;
printf("%c%c%c%c%c%c\n", letra[val][i-MIN], letra[k][j-MIN], letra[k2][h-MIN], letra[k3][l-MIN], letra[k4][m-MIN], letra[k5][n-MIN]);
cont++;
}
}
}
}
}
}
printf("Total de combinaciones: %d\n", cont);
}
void title() {
system("clear");
printf("-------------------------------------\n");
printf("| Generador de diccionarios |\n");
printf("| 1.0 |\n");
printf("| by luckyr13 |\n");
printf("-------------------------------------\n\n");
printf("Dudas, sugerencias y comentarios a: luckyr13@gmail.com\n");
}
sanshinron
04-15-2008, 10:48 AM
yea, and after you make that dictionary you would propably want to make a rainbow table out of it, cause it speeds up attacks... but it would take few months on a normal computer and btw it's already done... you can download alpha_num_sym32_space rainbow tables (34gb size) easier and faster, innit?
luckyr13
04-15-2008, 03:51 PM
well sounds good to me sanshinron, but if u know how many characters and what patron follows the password maybe u can save a few hd space generating ur own dictionary, isnt? ... like when u use hydra...
anyway ... is just an idea!
... eeehm... i have a doubt... how do u use rainbow tables in a program like hydra? :confused:
hhmatt81
04-15-2008, 08:55 PM
well sounds good to me sanshinron, but if u know how many characters and what patron follows the password maybe u can save a few hd space generating ur own dictionary, isnt? ... like when u use hydra...
anyway ... is just an idea!
... eeehm... i have a doubt... how do u use rainbow tables in a program like hydra? :confused:
I don't think hydra supports rainbow tables. Although I think l0phtcrack and john use them.
luckyr13
04-15-2008, 09:38 PM
ok hhmatt81 ... thanks for the information, i think the same thing ... by the way, do u ever try ophcrack? ... works really fine to me.
Ophcrack is a Windows password cracker based on rainbow tables. It is a very efficient implementation of rainbow tables done by the inventors of the method. It comes with a GTK+ Graphical User Interface and runs on Windows, Mac OS X (Intel CPU) as well as on Linux.
The ophcrack LiveCD contains a small linux system (SLAX6), ophcrack for linux and rainbow tables for alphanumerical passwords.
The liveCD cracks passwords automatically, no installation necessary, no admin password necessary (as long as you can boot from CD).
Windows Vista SAM can also be cracked.
Anyway bruteforce seems to be the last source but hope my program helps a little ;)
hhmatt81
04-16-2008, 07:47 AM
Here I did my best to translate it to english. I didn't understand what you were trying to say in the last line of the Description and the last line in your Note, so I left it in spanish maybe you could help translate this.
I also cleaned up the comments at the top of the code a little bit. To make it easier for me to translate it.
Just a little constructive criticism, I think the code could be written differently but I'm unsure how it's done. Recursive perhaps? It would take some of the redundant code out and make it a lot shorter and a lot cleaner. I know I've seen similar programs written in a different way that did the exact same thing I just forget how its done.
/************************************************** ****************/
/*
Dictionary Generator
Version: 1.0
Author: luckyr13
*/
/*
Descrption: Program that prints all the possible combinations
for words of 1 to 6 characters,
useful in testing of dictionary based attacks.
*/
/*
Compile for Linux: gcc com.c -o com
To run: ./com
To output to a file: ./com > dictionary.txt
Note: For large number combinations the int value will sometimes read an error like buffer overflow.
/************************************************** ****************/
#include <stdio.h>
//print all possible combinations (numbers, letters, symbols)
//#define MIN 30
//#define MAX 127
//print all binary combinations
//#define MIN 48
//#define MAX 50
//print all CAPITAL letter combinations
//#define MIN 65
//#define MAX 91
//print all lowercase letter combinations
//#define MIN 97
//#define MAX 123
//print all number combinations
#define MIN 48
#define MAX 58
void title();
void one();
void two();
void three();
void four();
void five();
void six();
int main() {
title();
int number=0;
printf("Enter the Number of characters in the password(1-6) : ");
scanf("%d", &number);
switch(number) {
case 1:
one();
break;
case 2:
two();
break;
case 3:
three();
break;
case 4:
four();
break;
case 5:
five();
break;
case 6:
six();
break;
default:
printf("Out of range, Enter a number between 1 and 6\n");
}
return 0;
}
void one() {
int limit=2;
int i=0;
int j=0;
int k=0;
int count=0;
int val=0;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
printf("%c\n", letter[val][i-MIN]);
count++;
}
printf("All of the combinations: %d\n", count);
}
void two() {
int limit=2;
int i=0;
int j=0;
int k=0;
int count=0;
int val=0;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letter[k][j-MIN]=j;
printf("%c%c\n", letter[val][i-MIN], letter[k][j-MIN]);
count++;
}
}
printf("All of the combinations: %d\n", count);
}
void three() {
int limit=3;
int i=0;
int j=0;
int h=0;
int count=0;
int val=0;
int k=val+1;
int k2=k+1;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letter[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letter[k2][h-MIN]=h;
printf("%c%c%c\n", letter[val][i-MIN], letter[k][j-MIN], letter[k2][h-MIN]);
count++;
}
}
}
printf("All of the combinations: %d\n", count);
}
void four() {
int limit=4;
int i=0;
int j=0;
int h=0;
int l=0;
int count=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letter[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letter[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letter[k3][l-MIN]=l;
printf("%c%c%c%c\n", letter[val][i-MIN], letter[k][j-MIN], letter[k2][h-MIN], letter[k3][l-MIN]);
count++;
}
}
}
}
printf("All of the combinations: %d\n", count);
}
void five() {
int limit=5;
int i=0;
int j=0;
int h=0;
int l=0;
int m=0;
int count=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
int k4=k3+1;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letter[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letter[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letter[k3][l-MIN]=l;
for(m=MIN; m<MAX; m++) {
letter[k4][m-MIN]=m;
printf("%c%c%c%c%c\n", letter[val][i-MIN], letter[k][j-MIN], letter[k2][h-MIN], letter[k3][l-MIN], letter[k4][m-MIN]);
count++;
}
}
}
}
}
printf("All of the combinations: %d\n", count);
}
void six() {
int limit=6;
int i=0;
int j=0;
int h=0;
int l=0;
int m=0;
int n=0;
int count=0;
int val=0;
int k=val+1;
int k2=k+1;
int k3=k2+1;
int k4=k3+1;
int k5= k4+1;
//int num=0;
char letter[limit][MAX-MIN];
for(i=MIN; i<MAX; i++) {
letter[val][i-MIN]=i;
for(j=MIN; j<MAX; j++) {
letter[k][j-MIN]=j;
for(h=MIN; h<MAX; h++) {
letter[k2][h-MIN]=h;
for(l=MIN; l<MAX; l++) {
letter[k3][l-MIN]=l;
for(m=MIN; m<MAX; m++) {
letter[k4][m-MIN]=m;
for(n=MIN; n<MAX; n++) {
letter[k5][n-MIN]=n;
printf("%c%c%c%c%c%c\n", letter[val][i-MIN], letter[k][j-MIN], letter[k2][h-MIN], letter[k3][l-MIN], letter[k4][m-MIN], letter[k5][n-MIN]);
count++;
}
}
}
}
}
}
printf("All of the combinations: %d\n", count);
}
void title() {
system("clear");
printf("-------------------------------------\n");
printf("| Dictionary Generator |\n");
printf("| 1.0 |\n");
printf("| by luckyr13 |\n");
printf("-------------------------------------\n\n");
printf("Send suggestions and comments to: luckyr13@gmail.com\n");
luckyr13
04-16-2008, 10:50 AM
Here I did my best to translate it to english.
:D thanks for the help, you are very kind
I didn't understand what you were trying to say in the last line of the Description and the last line in your Note, so I left it in spanish maybe you could help translate this.
mmm... in the line where says: "auxiliar en pruebas de ataques basados en diccionario" I mean something like "helpful in tests of dictionary based attacks"
Also in the comments I suggest how to compile in Linux (maybe obvious, but you never know if someone is new or something like that):
"Para compilar en Linux: gcc com.c -o com
Para correrlo: ./com
Para almacenarlo: ./com > diccionario.txt
Nota: Para numeros de combinaciones muy altas el contador
final truena debido a las restricciones de los int"
I mean something like:
"For compile in Linux: gcc code.c -o program
For running: ./program
For storage the information generated by the program: ./program > dictionary.txt
Note: For bigger combinations that int value doesnt allow the program will print an error (some like an overflow for the int variable called count)"
I also cleaned up the comments at the top of the code a little bit. To make it easier for me to translate it.
be my guest :)
Just a little constructive criticism, I think the code could be written differently but I'm unsure how it's done. Recursive perhaps? It would take some of the redundant code out and make it a lot shorter and a lot cleaner. I know I've seen similar programs written in a different way that did the exact same thing I just forget how its done.
You are correct... I need to code a better version for this program, actually I guess that there are a few variables that arent needed :eek: ... I will try to follow your advise (the recursive idea) and hope can upload an updated version in this week, its very important to make quality code and I guess that this one isnt that good ... only a doubt... do you think that this program is useful?. If more people considered useful could be important work on it, but you are right ... there are many programs that do the same, I dont know why I create one by myself :confused: maybe in that time (about two days ago) i find it interesting.
Anyway... I will try to publish more programs, maybe could be useful.
Oh... and again, thanks for your time hhmatt81, Im barely new around here so I feel a good sensation having comunication with someone :)
hhmatt81
04-16-2008, 11:30 AM
Ahh I see the translations now, makes sense. I'll update it now. I'm not the most fluent in spanish but I know a little.
You could just declare count/cont as long int instead on the longer dictionary words that should remove any overflow issues you may encounter.
I also thought that if your getting the user's input for the length then you might as well let them go higher than 6 but this would require a complete revamp of your code. With some bounds checking of course, you wouldn't want a newb to enter a number like 1 million for the character lengths.
thorin
04-16-2008, 04:39 PM
Ok couple of ideas/questions for you. My C is rusty so if I'm just plain wrong about something feel free to call BS on me.
1) Instead of using 6 fuctions that all do the same thing why not use one and pass it a length? ie: gen(1) or gen(6) depending on the input from the user.
2) For single chars why bother with the array? You just end up wasting memory when you could just output single chars.
3) Though the memory "should" be freed when the program completes you never actually destroy the array.
4) Consider your 2 char code (and this applies all the way up). You end up with a 2x10 array (as the code is commented/posted here). Since you end up outputting the array as single characters anyway why not just store them as single characters to begin with or even better simply use your counter values? ie: Since you only care about output and not storage/reuse you could just simply use your counter variables and not store the values at all. i.e.: printf("%c%c\n", i, j);
Example:
#include<stdio.h>
main()
{
int MIN=48;
int MAX=58;
int limit=2;
int i=0;
int j=0;
int count=0;
for(i=MIN; i<MAX; i++) {
for(j=MIN; j<MAX; j++) {
printf("%c%c\n", i, j);
count++;
}
}
printf("All of the combinations: %d\n", count);
}
bhups
05-12-2008, 05:06 PM
Hi, I am VERY interested in this application.
From what i understand, this applications goes through all combinations from A, B, C, D all the way to ZZZZZZZZ in caps, nocaps and with charectors and numbers...
this is correct?
shamanvirtuel
05-13-2008, 12:55 AM
why code AGAIN something that works really good and that is included in BT ? i mean there's crunch , and after you can use john to multiply your wordlist ....
luckyr13
05-14-2008, 08:29 AM
Hi... im just want to respond to a few comments...
for thorin:
1) Instead of using 6 fuctions that all do the same thing why not use one and pass it a length? ie: gen(1) or gen(6) depending on the input from the user.
well... i check the code and actually i didnt find how to make less code... maybe we can put all in one function but i guess thats the same that if we have 6 or more functions...
2) For single chars why bother with the array? You just end up [QUOTE]wasting memory when you could just output single chars.
youre right...
4) Consider your 2 char code (and this applies all the way up). You end up with a 2x10 array (as the code is commented/posted here). Since you end up outputting the array as single characters anyway why not just store them as single characters to begin with or even better simply use your counter values? ie: Since you only care about output and not storage/reuse you could just simply use your counter variables and not store the values at all. i.e.: printf("%c%c\n", i, j);
lol... yes, youre right :D
for hhmatt81:
Just a little constructive criticism, I think the code could be written differently but I'm unsure how it's done. Recursive perhaps? It would take some of the redundant code out and make it a lot shorter and a lot cleaner. I know I've seen similar programs written in a different way that did the exact same thing I just forget how its done.
well... i didnt find a solution of how to make the code recursive... maybe i need a little help because i think that im missing something... actually if you insert a string as a parameter in a function you can use an array and make all possible combinations of that string... but i didnt find how to make it works for my code... :(
for bhups:
Hi, I am VERY interested in this application.
From what i understand, this applications goes through all combinations from A, B, C, D all the way to ZZZZZZZZ in caps, nocaps and with charectors and numbers...
this is correct?
something like that... anyway i will post the base code to the end of this ... and maybe you can make it works for your own necesity... any comment im to your service...
the code goes through all the combinations that you define in the static variables called MIN and MAX... also i suggest a few ranges... you should made the calculation to know how many words you will have with a combination.
Something like:
n=number of the range of values (if you need all the combination for the numbers 0 to 9... n=10)
c=number of the long of the word (the string, if u need all the combinations for 4 characters... like 0000, 0001, 0002.... c=4)
n^c = number of combinations that you will have
for shamanvirtuel:
why code AGAIN something that works really good and that is included in BT ? i mean there's crunch , and after you can use john to multiply your wordlist ....
well... maybe just because i want to check the algorithm behind the idea of a password generator... i guess that are better codes or tools than my code... :D but if someone doesnt find it... could use mine.
-------------------------------------------------------------------
Well this is the final version of the idea with 5 functions, it doesnt include the comments because i hope that hhmatt81 could make another revision :):
#include <stdio.h>
//print all possible combinations (numbers, letters, symbols)
//#define MIN 30
//#define MAX 127
//print all binary combinations
//#define MIN 48
//#define MAX 50
//print all CAPITAL letter combinations
//#define MIN 65
//#define MAX 91
//print all lowercase letter combinations
//#define MIN 97
//#define MAX 123
//print all number combinations
#define MIN 48
#define MAX 58
void title();
void one();
void two();
void three();
void four();
void five();
int main() {
title();
int number=0;
printf("Enter the Number of characters in the password(1-5) : ");
scanf("%d", &number);
switch(number) {
case 1:
one();
break;
case 2:
two();
break;
case 3:
three();
break;
case 4:
four();
break;
case 5:
five();
break;
default:
printf("Out of range, Enter a number between 1 and 5\n");
}
return 0;
}
void one() {
int i=0;
for(i=MIN; i<MAX; i++) {
printf("%c\n", i);
}
}
void two() {
int i=0;
int j=0;
for(i=MIN; i<MAX; i++) {
for(j=MIN; j<MAX; j++) {
printf("%c%c\n", i, j);
}
}
}
void three() {
int i=0;
int j=0;
int k=0;
for(i=MIN; i<MAX; i++) {
for(j=MIN; j<MAX; j++) {
for(k=MIN; k<MAX; k++) {
printf("%c%c%c\n", i,j,k);
}
}
}
}
void four() {
int i=0;
int j=0;
int k=0;
int l=0;
for(i=MIN; i<MAX; i++) {
for(j=MIN; j<MAX; j++) {
for(k=MIN; k<MAX; k++) {
for(l=MIN; l<MAX; l++) {
printf("%c%c%c%c\n", i,j,k,l);
}
}
}
}
}
void five() {
int i=0;
int j=0;
int k=0;
int l=0;
int m=0;
for(i=MIN; i<MAX; i++) {
for(j=MIN; j<MAX; j++) {
for(k=MIN; k<MAX; k++) {
for(l=MIN; l<MAX; l++) {
for(m=MIN; m<MAX; m++) {
printf("%c%c%c%c%c\n", i,j,k,l,m);
}
}
}
}
}
}
void title() {
system("clear");
printf("-------------------------------------\n");
printf("| Dictionary Generator |\n");
printf("| 1.0 |\n");
printf("| by luckyr13 |\n");
printf("-------------------------------------\n\n");
printf("Send suggestions and comments to: luckyr13@gmail.com\n");
}
the only way that i found of making all this with one function is using conditionals, but i dont find it very useful... with this version i guess that the code is a kind of less weird :)... and also isnt very difficult to make changes in there.
but... im open to comments... thanks anyway for all the comments and for readme :)
bhups
05-26-2008, 11:51 AM
This code is EXCELLENT!!!
it does ALMOST EVERYTHING i want it to do!
really appreciate the support mate.
do know how I can save the genereated txt to a file afterwards? i.e. txt file?
most of the lines are removed on CMD when i generate it.
i've modified the code to allow me to output up to 8 charectors. ;)
thanks again!
thorin
05-26-2008, 12:46 PM
do know how I can save the genereated txt to a file afterwards? i.e. txt file?See the original post, just do standard linux stdout redirection.
bhups
05-26-2008, 01:34 PM
i'm currently using Windows..
not to worry though.. found out how its done on CMD.
its similar to the first few posts.
"C:\app.exe > generated.txt"
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.